aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig366
-rw-r--r--arch/sh/Kconfig.cpu115
-rw-r--r--arch/sh/Kconfig.debug51
-rw-r--r--arch/sh/Makefile103
-rw-r--r--arch/sh/boards/cayman/Makefile5
-rw-r--r--arch/sh/boards/cayman/irq.c197
-rw-r--r--arch/sh/boards/cayman/led.c51
-rw-r--r--arch/sh/boards/cayman/setup.c187
-rw-r--r--arch/sh/boards/dreamcast/irq.c2
-rw-r--r--arch/sh/boards/dreamcast/setup.c8
-rw-r--r--arch/sh/boards/landisk/gio.c2
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/Kconfig12
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/Makefile8
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/io.c283
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/irq.c116
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/pci.c149
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/setup.c105
-rw-r--r--arch/sh/boards/renesas/r7780rp/Makefile2
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7780mp.c2
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7780rp.c52
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7785rp.c45
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq.c51
-rw-r--r--arch/sh/boards/renesas/r7780rp/setup.c10
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/irq.c8
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/setup.c161
-rw-r--r--arch/sh/boards/renesas/sdk7780/Kconfig23
-rw-r--r--arch/sh/boards/renesas/sdk7780/Makefile5
-rw-r--r--arch/sh/boards/renesas/sdk7780/irq.c46
-rw-r--r--arch/sh/boards/renesas/sdk7780/setup.c109
-rw-r--r--arch/sh/boot/Makefile18
-rw-r--r--arch/sh/boot/compressed/Makefile46
-rw-r--r--arch/sh/boot/compressed/Makefile_3243
-rw-r--r--arch/sh/boot/compressed/Makefile_6445
-rw-r--r--arch/sh/boot/compressed/cache.c12
-rw-r--r--arch/sh/boot/compressed/head_32.S (renamed from arch/sh/boot/compressed/head.S)0
-rw-r--r--arch/sh/boot/compressed/head_64.S163
-rw-r--r--arch/sh/boot/compressed/misc_32.c (renamed from arch/sh/boot/compressed/misc.c)5
-rw-r--r--arch/sh/boot/compressed/misc_64.c250
-rw-r--r--arch/sh/boot/compressed/vmlinux_64.lds64
-rw-r--r--arch/sh/cchips/voyagergx/Makefile9
-rw-r--r--arch/sh/cchips/voyagergx/consistent.c121
-rw-r--r--arch/sh/cchips/voyagergx/irq.c101
-rw-r--r--arch/sh/cchips/voyagergx/setup.c37
-rw-r--r--arch/sh/configs/cayman_defconfig1166
-rw-r--r--arch/sh/configs/hs7751rvoip_defconfig908
-rw-r--r--arch/sh/configs/r7785rp_defconfig13
-rw-r--r--arch/sh/configs/sdk7780_defconfig (renamed from arch/sh/configs/r7780rp_defconfig)1088
-rw-r--r--arch/sh/configs/se7712_defconfig2
-rw-r--r--arch/sh/drivers/dma/Kconfig2
-rw-r--r--arch/sh/drivers/dma/dma-sh.c2
-rw-r--r--arch/sh/drivers/pci/Makefile7
-rw-r--r--arch/sh/drivers/pci/dma-dreamcast.c70
-rw-r--r--arch/sh/drivers/pci/fixups-dreamcast.c10
-rw-r--r--arch/sh/drivers/pci/fixups-sdk7780.c59
-rw-r--r--arch/sh/drivers/pci/ops-cayman.c94
-rw-r--r--arch/sh/drivers/pci/ops-r7780rp.c16
-rw-r--r--arch/sh/drivers/pci/ops-sdk7780.c73
-rw-r--r--arch/sh/drivers/pci/ops-sh5.c93
-rw-r--r--arch/sh/drivers/pci/pci-auto.c2
-rw-r--r--arch/sh/drivers/pci/pci-sh4.h4
-rw-r--r--arch/sh/drivers/pci/pci-sh5.c228
-rw-r--r--arch/sh/drivers/pci/pci-sh5.h113
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c1
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.h1
-rw-r--r--arch/sh/drivers/pci/pci.c2
-rw-r--r--arch/sh/kernel/Makefile30
-rw-r--r--arch/sh/kernel/Makefile_3226
-rw-r--r--arch/sh/kernel/Makefile_6422
-rw-r--r--arch/sh/kernel/cpu/Makefile6
-rw-r--r--arch/sh/kernel/cpu/init.c74
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile4
-rw-r--r--arch/sh/kernel/cpu/irq/intc-sh5.c257
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c31
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S19
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7203.c89
-rw-r--r--arch/sh/kernel/cpu/sh2a/fpu.c633
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c22
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7203.c319
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c2
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile2
-rw-r--r--arch/sh/kernel/cpu/sh3/clock-sh7712.c71
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S24
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S2
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c9
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c10
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh770x.c11
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c16
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7720.c78
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile2
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c537
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c2
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c18
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c13
-rw-r--r--arch/sh/kernel/cpu/sh4/softfloat.c892
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7763.c126
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c10
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7763.c390
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c13
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c19
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c14
-rw-r--r--arch/sh/kernel/cpu/sh5/Makefile7
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2101
-rw-r--r--arch/sh/kernel/cpu/sh5/fpu.c166
-rw-r--r--arch/sh/kernel/cpu/sh5/probe.c76
-rw-r--r--arch/sh/kernel/cpu/sh5/switchto.S198
-rw-r--r--arch/sh/kernel/cpu/sh5/unwind.c326
-rw-r--r--arch/sh/kernel/dump_task.c31
-rw-r--r--arch/sh/kernel/early_printk.c12
-rw-r--r--arch/sh/kernel/entry-common.S27
-rw-r--r--arch/sh/kernel/head_32.S (renamed from arch/sh/kernel/head.S)6
-rw-r--r--arch/sh/kernel/head_64.S356
-rw-r--r--arch/sh/kernel/init_task.c4
-rw-r--r--arch/sh/kernel/io.c67
-rw-r--r--arch/sh/kernel/module.c62
-rw-r--r--arch/sh/kernel/process_32.c (renamed from arch/sh/kernel/process.c)93
-rw-r--r--arch/sh/kernel/process_64.c701
-rw-r--r--arch/sh/kernel/ptrace_32.c (renamed from arch/sh/kernel/ptrace.c)21
-rw-r--r--arch/sh/kernel/ptrace_64.c341
-rw-r--r--arch/sh/kernel/setup.c39
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c (renamed from arch/sh/kernel/sh_ksyms.c)0
-rw-r--r--arch/sh/kernel/sh_ksyms_64.c55
-rw-r--r--arch/sh/kernel/signal_32.c (renamed from arch/sh/kernel/signal.c)18
-rw-r--r--arch/sh/kernel/signal_64.c751
-rw-r--r--arch/sh/kernel/sys_sh.c100
-rw-r--r--arch/sh/kernel/sys_sh32.c84
-rw-r--r--arch/sh/kernel/sys_sh64.c66
-rw-r--r--arch/sh/kernel/syscalls_32.S (renamed from arch/sh/kernel/syscalls.S)0
-rw-r--r--arch/sh/kernel/syscalls_64.S381
-rw-r--r--arch/sh/kernel/time_32.c (renamed from arch/sh/kernel/time.c)0
-rw-r--r--arch/sh/kernel/time_64.c519
-rw-r--r--arch/sh/kernel/timers/timer-cmt.c4
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c1
-rw-r--r--arch/sh/kernel/traps.c949
-rw-r--r--arch/sh/kernel/traps_32.c919
-rw-r--r--arch/sh/kernel/traps_64.c975
-rw-r--r--arch/sh/kernel/vmlinux.lds.S139
-rw-r--r--arch/sh/kernel/vmlinux_32.lds.S152
-rw-r--r--arch/sh/kernel/vmlinux_64.lds.S164
-rw-r--r--arch/sh/lib/Makefile5
-rw-r--r--arch/sh/lib/clear_page.S (renamed from arch/sh/mm/clear_page.S)8
-rw-r--r--arch/sh/lib/copy_page.S (renamed from arch/sh/mm/copy_page.S)9
-rw-r--r--arch/sh/lib/io.c82
-rw-r--r--arch/sh/lib64/.gitignore1
-rw-r--r--arch/sh/lib64/Makefile15
-rw-r--r--arch/sh/lib64/c-checksum.c214
-rw-r--r--arch/sh/lib64/clear_page.S54
-rw-r--r--arch/sh/lib64/copy_page.S89
-rw-r--r--arch/sh/lib64/copy_user_memcpy.S217
-rw-r--r--arch/sh/lib64/dbg.c430
-rw-r--r--arch/sh/lib64/memcpy.c81
-rw-r--r--arch/sh/lib64/panic.c58
-rw-r--r--arch/sh/lib64/udelay.c56
-rw-r--r--arch/sh/mm/Kconfig222
-rw-r--r--arch/sh/mm/Makefile40
-rw-r--r--arch/sh/mm/Makefile_3236
-rw-r--r--arch/sh/mm/Makefile_6444
-rw-r--r--arch/sh/mm/cache-debugfs.c9
-rw-r--r--arch/sh/mm/cache-sh4.c14
-rw-r--r--arch/sh/mm/cache-sh5.c1029
-rw-r--r--arch/sh/mm/cache-sh7705.c12
-rw-r--r--arch/sh/mm/consistent.c174
-rw-r--r--arch/sh/mm/extable_32.c (renamed from arch/sh/mm/extable.c)0
-rw-r--r--arch/sh/mm/extable_64.c82
-rw-r--r--arch/sh/mm/fault_32.c (renamed from arch/sh/mm/fault.c)2
-rw-r--r--arch/sh/mm/fault_64.c275
-rw-r--r--arch/sh/mm/init.c68
-rw-r--r--arch/sh/mm/ioremap_32.c (renamed from arch/sh/mm/ioremap.c)0
-rw-r--r--arch/sh/mm/ioremap_64.c404
-rw-r--r--arch/sh/mm/pg-nommu.c4
-rw-r--r--arch/sh/mm/pmb.c26
-rw-r--r--arch/sh/mm/tlb-nommu.c10
-rw-r--r--arch/sh/mm/tlb-sh4.c7
-rw-r--r--arch/sh/mm/tlb-sh5.c164
-rw-r--r--arch/sh/mm/tlbflush_32.c (renamed from arch/sh/mm/tlb-flush.c)0
-rw-r--r--arch/sh/mm/tlbflush_64.c475
-rw-r--r--arch/sh/tools/mach-types2
179 files changed, 20392 insertions, 4880 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 496d635f89b2..1cd9c8fd927d 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -6,8 +6,7 @@
mainmenu "Linux/SuperH Kernel Configuration"
config SUPERH
- bool
- default y
+ def_bool y
select EMBEDDED
help
The SuperH is a RISC processor targeted for use in embedded systems
@@ -15,36 +14,36 @@ config SUPERH
gaming console. The SuperH port has a home page at
<http://www.linux-sh.org/>.
+config SUPERH32
+ def_bool !SUPERH64
+
+config SUPERH64
+ def_bool y if CPU_SH5
+
config RWSEM_GENERIC_SPINLOCK
- bool
- default y
+ def_bool y
config RWSEM_XCHGADD_ALGORITHM
bool
config GENERIC_BUG
def_bool y
- depends on BUG
+ depends on BUG && SUPERH32
config GENERIC_FIND_NEXT_BIT
- bool
- default y
+ def_bool y
config GENERIC_HWEIGHT
- bool
- default y
+ def_bool y
config GENERIC_HARDIRQS
- bool
- default y
+ def_bool y
config GENERIC_IRQ_PROBE
- bool
- default y
+ def_bool y
config GENERIC_CALIBRATE_DELAY
- bool
- default y
+ def_bool y
config GENERIC_IOMAP
bool
@@ -75,20 +74,16 @@ config ARCH_MAY_HAVE_PC_FDC
bool
config STACKTRACE_SUPPORT
- bool
- default y
+ def_bool y
config LOCKDEP_SUPPORT
- bool
- default y
+ def_bool y
config ARCH_HAS_ILOG2_U32
- bool
- default n
+ def_bool n
config ARCH_HAS_ILOG2_U64
- bool
- default n
+ def_bool n
config ARCH_NO_VIRT_TO_BUS
def_bool y
@@ -97,110 +92,234 @@ source "init/Kconfig"
menu "System type"
-source "arch/sh/mm/Kconfig"
+#
+# Processor families
+#
+config CPU_SH2
+ bool
-menu "Processor features"
+config CPU_SH2A
+ bool
+ select CPU_SH2
+
+config CPU_SH3
+ bool
+ select CPU_HAS_INTEVT
+ select CPU_HAS_SR_RB
+
+config CPU_SH4
+ bool
+ select CPU_HAS_INTEVT
+ select CPU_HAS_SR_RB
+ select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
+ select CPU_HAS_FPU if !CPU_SH4AL_DSP
+
+config CPU_SH4A
+ bool
+ select CPU_SH4
+
+config CPU_SH4AL_DSP
+ bool
+ select CPU_SH4A
+ select CPU_HAS_DSP
+
+config CPU_SH5
+ bool
+ select CPU_HAS_FPU
+
+config CPU_SHX2
+ bool
+
+config CPU_SHX3
+ bool
choice
- prompt "Endianess selection"
- default CPU_LITTLE_ENDIAN
- help
- Some SuperH machines can be configured for either little or big
- endian byte order. These modes require different kernels.
+ prompt "Processor sub-type selection"
-config CPU_LITTLE_ENDIAN
- bool "Little Endian"
+#
+# Processor subtypes
+#
-config CPU_BIG_ENDIAN
- bool "Big Endian"
+# SH-2 Processor Support
-endchoice
+config CPU_SUBTYPE_SH7619
+ bool "Support SH7619 processor"
+ select CPU_SH2
+
+# SH-2A Processor Support
+
+config CPU_SUBTYPE_SH7203
+ bool "Support SH7203 processor"
+ select CPU_SH2A
+ select CPU_HAS_FPU
+
+config CPU_SUBTYPE_SH7206
+ bool "Support SH7206 processor"
+ select CPU_SH2A
-config SH_FPU
- bool "FPU support"
- depends on CPU_HAS_FPU
- default y
+config CPU_SUBTYPE_SH7263
+ bool "Support SH7263 processor"
+ select CPU_SH2A
+ select CPU_HAS_FPU
+
+# SH-3 Processor Support
+
+config CPU_SUBTYPE_SH7705
+ bool "Support SH7705 processor"
+ select CPU_SH3
+
+config CPU_SUBTYPE_SH7706
+ bool "Support SH7706 processor"
+ select CPU_SH3
help
- Selecting this option will enable support for SH processors that
- have FPU units (ie, SH77xx).
+ Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
- This option must be set in order to enable the FPU.
+config CPU_SUBTYPE_SH7707
+ bool "Support SH7707 processor"
+ select CPU_SH3
+ help
+ Select SH7707 if you have a 60 Mhz SH-3 HD6417707 CPU.
-config SH_FPU_EMU
- bool "FPU emulation support"
- depends on !SH_FPU && EXPERIMENTAL
- default n
+config CPU_SUBTYPE_SH7708
+ bool "Support SH7708 processor"
+ select CPU_SH3
help
- Selecting this option will enable support for software FPU emulation.
- Most SH-3 users will want to say Y here, whereas most SH-4 users will
- want to say N.
+ Select SH7708 if you have a 60 Mhz SH-3 HD6417708S or
+ if you have a 100 Mhz SH-3 HD6417708R CPU.
-config SH_DSP
- bool "DSP support"
- depends on CPU_HAS_DSP
- default y
+config CPU_SUBTYPE_SH7709
+ bool "Support SH7709 processor"
+ select CPU_SH3
help
- Selecting this option will enable support for SH processors that
- have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
+ Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
- This option must be set in order to enable the DSP.
+config CPU_SUBTYPE_SH7710
+ bool "Support SH7710 processor"
+ select CPU_SH3
+ select CPU_HAS_DSP
+ help
+ Select SH7710 if you have a SH3-DSP SH7710 CPU.
-config SH_ADC
- bool "ADC support"
- depends on CPU_SH3
- default y
+config CPU_SUBTYPE_SH7712
+ bool "Support SH7712 processor"
+ select CPU_SH3
+ select CPU_HAS_DSP
help
- Selecting this option will allow the Linux kernel to use SH3 on-chip
- ADC module.
+ Select SH7712 if you have a SH3-DSP SH7712 CPU.
- If unsure, say N.
+config CPU_SUBTYPE_SH7720
+ bool "Support SH7720 processor"
+ select CPU_SH3
+ select CPU_HAS_DSP
+ help
+ Select SH7720 if you have a SH3-DSP SH7720 CPU.
-config SH_STORE_QUEUES
- bool "Support for Store Queues"
- depends on CPU_SH4
+config CPU_SUBTYPE_SH7721
+ bool "Support SH7721 processor"
+ select CPU_SH3
+ select CPU_HAS_DSP
help
- Selecting this option will enable an in-kernel API for manipulating
- the store queues integrated in the SH-4 processors.
+ Select SH7721 if you have a SH3-DSP SH7721 CPU.
-config SPECULATIVE_EXECUTION
- bool "Speculative subroutine return"
- depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
+# SH-4 Processor Support
+
+config CPU_SUBTYPE_SH7750
+ bool "Support SH7750 processor"
+ select CPU_SH4
help
- This enables support for a speculative instruction fetch for
- subroutine return. There are various pitfalls associated with
- this, as outlined in the SH7780 hardware manual.
+ Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
- If unsure, say N.
+config CPU_SUBTYPE_SH7091
+ bool "Support SH7091 processor"
+ select CPU_SH4
+ help
+ Select SH7091 if you have an SH-4 based Sega device (such as
+ the Dreamcast, Naomi, and Naomi 2).
-config CPU_HAS_INTEVT
- bool
+config CPU_SUBTYPE_SH7750R
+ bool "Support SH7750R processor"
+ select CPU_SH4
-config CPU_HAS_MASKREG_IRQ
- bool
+config CPU_SUBTYPE_SH7750S
+ bool "Support SH7750S processor"
+ select CPU_SH4
-config CPU_HAS_IPR_IRQ
- bool
+config CPU_SUBTYPE_SH7751
+ bool "Support SH7751 processor"
+ select CPU_SH4
+ help
+ Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
+ or if you have a HD6417751R CPU.
-config CPU_HAS_SR_RB
- bool
+config CPU_SUBTYPE_SH7751R
+ bool "Support SH7751R processor"
+ select CPU_SH4
+
+config CPU_SUBTYPE_SH7760
+ bool "Support SH7760 processor"
+ select CPU_SH4
+
+config CPU_SUBTYPE_SH4_202
+ bool "Support SH4-202 processor"
+ select CPU_SH4
+
+# SH-4A Processor Support
+
+config CPU_SUBTYPE_SH7763
+ bool "Support SH7763 processor"
+ select CPU_SH4A
help
- This will enable the use of SR.RB register bank usage. Processors
- that are lacking this bit must have another method in place for
- accomplishing what is taken care of by the banked registers.
+ Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
- See <file:Documentation/sh/register-banks.txt> for further
- information on SR.RB and register banking in the kernel in general.
+config CPU_SUBTYPE_SH7770
+ bool "Support SH7770 processor"
+ select CPU_SH4A
-config CPU_HAS_PTEA
- bool
+config CPU_SUBTYPE_SH7780
+ bool "Support SH7780 processor"
+ select CPU_SH4A
-config CPU_HAS_DSP
- bool
+config CPU_SUBTYPE_SH7785
+ bool "Support SH7785 processor"
+ select CPU_SH4A
+ select CPU_SHX2
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
-config CPU_HAS_FPU
- bool
+config CPU_SUBTYPE_SHX3
+ bool "Support SH-X3 processor"
+ select CPU_SH4A
+ select CPU_SHX3
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
+ select SYS_SUPPORTS_SMP
-endmenu
+# SH4AL-DSP Processor Support
+
+config CPU_SUBTYPE_SH7343
+ bool "Support SH7343 processor"
+ select CPU_SH4AL_DSP
+
+config CPU_SUBTYPE_SH7722
+ bool "Support SH7722 processor"
+ select CPU_SH4AL_DSP
+ select CPU_SHX2
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
+
+# SH-5 Processor Support
+
+config CPU_SUBTYPE_SH5_101
+ bool "Support SH5-101 processor"
+ select CPU_SH5
+
+config CPU_SUBTYPE_SH5_103
+ bool "Support SH5-103 processor"
+
+endchoice
+
+source "arch/sh/mm/Kconfig"
+source "arch/sh/Kconfig.cpu"
menu "Board support"
@@ -321,13 +440,6 @@ config SH_SECUREEDGE5410
This includes both the OEM SecureEdge products as well as the
SME product line.
-config SH_HS7751RVOIP
- bool "HS7751RVOIP"
- depends on CPU_SUBTYPE_SH7751R
- help
- Select HS7751RVOIP if configuring for a Renesas Technology
- Sales VoIP board.
-
config SH_7710VOIPGW
bool "SH7710-VOIP-GW"
depends on CPU_SUBTYPE_SH7710
@@ -343,6 +455,14 @@ config SH_RTS7751R2D
Select RTS7751R2D if configuring for a Renesas Technology
Sales SH-Graphics board.
+config SH_SDK7780
+ bool "SDK7780R3"
+ depends on CPU_SUBTYPE_SH7780
+ select SYS_SUPPORTS_PCI
+ help
+ Select SDK7780 if configuring for a Renesas SH7780 SDK7780R3
+ evaluation board.
+
config SH_HIGHLANDER
bool "Highlander"
depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
@@ -399,41 +519,47 @@ config SH_MAGIC_PANEL_R2
help
Select Magic Panel R2 if configuring for Magic Panel R2.
+config SH_CAYMAN
+ bool "Hitachi Cayman"
+ depends on CPU_SUBTYPE_SH5_101 || CPU_SUBTYPE_SH5_103
+ select SYS_SUPPORTS_PCI
+
endmenu
-source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
source "arch/sh/boards/renesas/r7780rp/Kconfig"
+source "arch/sh/boards/renesas/sdk7780/Kconfig"
source "arch/sh/boards/magicpanelr2/Kconfig"
menu "Timer and clock configuration"
config SH_TMU
- bool "TMU timer support"
+ def_bool y
+ prompt "TMU timer support"
depends on CPU_SH3 || CPU_SH4
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
- default y
help
This enables the use of the TMU as the system timer.
config SH_CMT
- bool "CMT timer support"
+ def_bool y
+ prompt "CMT timer support"
depends on CPU_SH2
- default y
help
This enables the use of the CMT as the system timer.
config SH_MTU2
- bool "MTU2 timer support"
+ def_bool n
+ prompt "MTU2 timer support"
depends on CPU_SH2A
- default n
help
This enables the use of the MTU2 as the system timer.
config SH_TIMER_IRQ
int
- default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
+ default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 || \
+ CPU_SUBTYPE_SH7763
default "86" if CPU_SUBTYPE_SH7619
default "140" if CPU_SUBTYPE_SH7206
default "16"
@@ -445,7 +571,8 @@ config SH_PCLK_FREQ
default "32000000" if CPU_SUBTYPE_SH7722
default "33333333" if CPU_SUBTYPE_SH7770 || \
CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
- CPU_SUBTYPE_SH7206
+ CPU_SUBTYPE_SH7203 || CPU_SUBTYPE_SH7206 || \
+ CPU_SUBTYPE_SH7263
default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R
default "66000000" if CPU_SUBTYPE_SH4_202
default "50000000"
@@ -456,7 +583,7 @@ config SH_PCLK_FREQ
config SH_CLK_MD
int "CPU Mode Pin Setting"
- depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
+ depends on CPU_SH2
default 6 if CPU_SUBTYPE_SH7206
default 5 if CPU_SUBTYPE_SH7619
default 0
@@ -490,9 +617,8 @@ source "arch/sh/drivers/Kconfig"
endmenu
config ISA_DMA_API
- bool
+ def_bool y
depends on SH_MPC1211
- default y
menu "Kernel features"
@@ -570,7 +696,7 @@ source "kernel/Kconfig.preempt"
config GUSA
def_bool y
- depends on !SMP
+ depends on !SMP && SUPERH32
help
This enables support for gUSA (general UserSpace Atomicity).
This is the default implementation for both UP and non-ll/sc
@@ -582,6 +708,16 @@ config GUSA
This should only be disabled for special cases where alternate
atomicity implementations exist.
+config GUSA_RB
+ bool "Implement atomic operations by roll-back (gRB) (EXPERIMENTAL)"
+ depends on GUSA && CPU_SH3 || (CPU_SH4 && !CPU_SH4A)
+ help
+ Enabling this option will allow the kernel to implement some
+ atomic operations using a software implemention of load-locked/
+ store-conditional (LLSC). On machines which do not have hardware
+ LLSC, this should be more efficient than the other alternative of
+ disabling insterrupts around the atomic sequence.
+
endmenu
menu "Boot options"
diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
new file mode 100644
index 000000000000..d850184d0694
--- /dev/null
+++ b/arch/sh/Kconfig.cpu
@@ -0,0 +1,115 @@
+menu "Processor features"
+
+choice
+ prompt "Endianess selection"
+ default CPU_LITTLE_ENDIAN
+ help
+ Some SuperH machines can be configured for either little or big
+ endian byte order. These modes require different kernels.
+
+config CPU_LITTLE_ENDIAN
+ bool "Little Endian"
+
+config CPU_BIG_ENDIAN
+ bool "Big Endian"
+
+endchoice
+
+config SH_FPU
+ def_bool y
+ prompt "FPU support"
+ depends on CPU_HAS_FPU
+ help
+ Selecting this option will enable support for SH processors that
+ have FPU units (ie, SH77xx).
+
+ This option must be set in order to enable the FPU.
+
+config SH64_FPU_DENORM_FLUSH
+ bool "Flush floating point denorms to zero"
+ depends on SH_FPU && SUPERH64
+
+config SH_FPU_EMU
+ def_bool n
+ prompt "FPU emulation support"
+ depends on !SH_FPU && EXPERIMENTAL
+ help
+ Selecting this option will enable support for software FPU emulation.
+ Most SH-3 users will want to say Y here, whereas most SH-4 users will
+ want to say N.
+
+config SH_DSP
+ def_bool y
+ prompt "DSP support"
+ depends on CPU_HAS_DSP
+ help
+ Selecting this option will enable support for SH processors that
+ have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
+
+ This option must be set in order to enable the DSP.
+
+config SH_ADC
+ def_bool y
+ prompt "ADC support"
+ depends on CPU_SH3
+ help
+ Selecting this option will allow the Linux kernel to use SH3 on-chip
+ ADC module.
+
+ If unsure, say N.
+
+config SH_STORE_QUEUES
+ bool "Support for Store Queues"
+ depends on CPU_SH4
+ help
+ Selecting this option will enable an in-kernel API for manipulating
+ the store queues integrated in the SH-4 processors.
+
+config SPECULATIVE_EXECUTION
+ bool "Speculative subroutine return"
+ depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
+ help
+ This enables support for a speculative instruction fetch for
+ subroutine return. There are various pitfalls associated with
+ this, as outlined in the SH7780 hardware manual.
+
+ If unsure, say N.
+
+config SH64_USER_MISALIGNED_FIXUP
+ def_bool y
+ prompt "Fixup misaligned loads/stores occurring in user mode"
+ depends on SUPERH64
+
+config SH64_ID2815_WORKAROUND
+ bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
+ depends on CPU_SUBTYPE_SH5_101
+
+config CPU_HAS_INTEVT
+ bool
+
+config CPU_HAS_MASKREG_IRQ
+ bool
+
+config CPU_HAS_IPR_IRQ
+ bool
+
+config CPU_HAS_SR_RB
+ bool
+ help
+ This will enable the use of SR.RB register bank usage. Processors
+ that are lacking this bit must have another method in place for
+ accomplishing what is taken care of by the banked registers.
+
+ See <file:Documentation/sh/register-banks.txt> for further
+ information on SR.RB and register banking in the kernel in general.
+
+config CPU_HAS_PTEA
+ bool
+
+config CPU_HAS_DSP
+ bool
+
+config CPU_HAS_FPU
+ bool
+
+endmenu
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 722da6851f56..f7c716166ce8 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -1,8 +1,7 @@
menu "Kernel hacking"
config TRACE_IRQFLAGS_SUPPORT
- bool
- default y
+ def_bool y
source "lib/Kconfig.debug"
@@ -30,12 +29,13 @@ config EARLY_SCIF_CONSOLE
config EARLY_SCIF_CONSOLE_PORT
hex
depends on EARLY_SCIF_CONSOLE
- default "0xffe00000" if CPU_SUBTYPE_SH7780
+ default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763
default "0xffea0000" if CPU_SUBTYPE_SH7785
- default "0xfffe9800" if CPU_SUBTYPE_SH7206
+ default "0xfffe8000" if CPU_SUBTYPE_SH7203
+ default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
default "0xf8420000" if CPU_SUBTYPE_SH7619
default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
- default "0xa4430000" if CPU_SUBTYPE_SH7720
+ default "0xa4430000" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
default "0xffc30000" if CPU_SUBTYPE_SHX3
default "0xffe80000" if CPU_SH4
default "0x00000000"
@@ -62,7 +62,7 @@ config DEBUG_BOOTMEM
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
- depends on DEBUG_KERNEL
+ depends on DEBUG_KERNEL && SUPERH32
help
This option will cause messages to be printed if free stack space
drops below a certain limit.
@@ -88,7 +88,7 @@ config 4KSTACKS
config IRQSTACKS
bool "Use separate kernel stacks when processing interrupts"
- depends on DEBUG_KERNEL
+ depends on DEBUG_KERNEL && SUPERH32
help
If you say Y here the kernel will use separate kernel stacks
for handling hard and soft interrupts. This can help avoid
@@ -119,19 +119,19 @@ config COMPILE_OPTIONS
depends on MORE_COMPILE_OPTIONS
config KGDB_NMI
- bool "Enter KGDB on NMI"
- default n
+ def_bool n
+ prompt "Enter KGDB on NMI"
config SH_KGDB_CONSOLE
- bool "Console messages through GDB"
+ def_bool n
+ prompt "Console messages through GDB"
depends on !SERIAL_SH_SCI_CONSOLE && SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
- default n
config KGDB_SYSRQ
- bool "Allow SysRq 'G' to enter KGDB"
+ def_bool y
+ prompt "Allow SysRq 'G' to enter KGDB"
depends on MAGIC_SYSRQ
- default y
comment "Serial port setup"
@@ -174,4 +174,29 @@ endchoice
endmenu
+if SUPERH64
+
+config SH64_PROC_ASIDS
+ bool "Debug: report ASIDs through /proc/asids"
+ depends on PROC_FS
+
+config SH64_SR_WATCH
+ bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
+
+config POOR_MANS_STRACE
+ bool "Debug: enable rudimentary strace facility"
+ help
+ This option allows system calls to be traced to the console. It also
+ aids in detecting kernel stack underflow. It is useful for debugging
+ early-userland problems (e.g. init incurring fatal exceptions.)
+
+config SH_ALPHANUMERIC
+ bool "Enable debug outputs to on-board alphanumeric display"
+ depends on SH_CAYMAN
+
+config SH_NO_BSS_INIT
+ bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
+
+endif
+
endmenu
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index e189fae8b60c..17fc36186bf4 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -1,17 +1,13 @@
-# $Id: Makefile,v 1.35 2004/04/15 03:39:20 sugioka Exp $
#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
+# arch/sh/Makefile
#
# Copyright (C) 1999 Kaz Kojima
# Copyright (C) 2002, 2003, 2004 Paul Mundt
# Copyright (C) 2002 M. R. Brown
#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
#
isa-y := any
isa-$(CONFIG_SH_DSP) := sh
@@ -21,13 +17,9 @@ isa-$(CONFIG_CPU_SH3) := sh3
isa-$(CONFIG_CPU_SH4) := sh4
isa-$(CONFIG_CPU_SH4A) := sh4a
isa-$(CONFIG_CPU_SH4AL_DSP) := sh4al
-
+isa-$(CONFIG_CPU_SH5) := shmedia
isa-$(CONFIG_SH_DSP) := $(isa-y)-dsp
-ifndef CONFIG_MMU
-isa-y := $(isa-y)-nommu
-endif
-
ifndef CONFIG_SH_DSP
ifndef CONFIG_SH_FPU
isa-y := $(isa-y)-nofpu
@@ -44,6 +36,7 @@ cflags-$(CONFIG_CPU_SH4) := $(call cc-option,-m4,) \
$(call cc-option,-mno-implicit-fp,-m4-nofpu)
cflags-$(CONFIG_CPU_SH4A) += $(call cc-option,-m4a,) \
$(call cc-option,-m4a-nofpu,)
+cflags-$(CONFIG_CPU_SH5) := $(call cc-option,-m5-32media-nofpu,)
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
@@ -66,22 +59,27 @@ cflags-y += $(isaflags-y) -ffreestanding
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
-OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -R .stab -R .stabstr -S
+OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment \
+ -R .stab -R .stabstr -S
-#
-# arch/sh/defconfig doesn't reflect any real hardware, and as such should
-# never be used by anyone. Use a board-specific defconfig that has a
-# reasonable chance of being current instead.
-#
-KBUILD_DEFCONFIG := r7780rp_defconfig
+# Give the various platforms the opportunity to set default image types
+defaultimage-$(CONFIG_SUPERH32) := zImage
-KBUILD_IMAGE := arch/sh/boot/zImage
+# Set some sensible Kbuild defaults
+KBUILD_DEFCONFIG := r7780mp_defconfig
+KBUILD_IMAGE := $(defaultimage-y)
#
# Choosing incompatible machines durings configuration will result in
# error messages during linking.
#
-LDFLAGS_vmlinux += -e _stext
+ifdef CONFIG_SUPERH32
+LDFLAGS_vmlinux += -e _stext
+else
+LDFLAGS_vmlinux += --defsym phys_stext=_stext-$(CONFIG_PAGE_OFFSET) \
+ --defsym phys_stext_shmedia=phys_stext+1 \
+ -e phys_stext_shmedia
+endif
ifdef CONFIG_CPU_LITTLE_ENDIAN
LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64'
@@ -94,7 +92,9 @@ endif
KBUILD_CFLAGS += -pipe $(cflags-y)
KBUILD_AFLAGS += $(cflags-y)
-head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
+head-y := arch/sh/kernel/init_task.o
+head-$(CONFIG_SUPERH32) += arch/sh/kernel/head_32.o
+head-$(CONFIG_SUPERH64) += arch/sh/kernel/head_64.o
LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
@@ -112,11 +112,11 @@ machdir-$(CONFIG_SH_DREAMCAST) += dreamcast
machdir-$(CONFIG_SH_MPC1211) += mpc1211
machdir-$(CONFIG_SH_SH03) += sh03
machdir-$(CONFIG_SH_SECUREEDGE5410) += snapgear
-machdir-$(CONFIG_SH_HS7751RVOIP) += renesas/hs7751rvoip
machdir-$(CONFIG_SH_RTS7751R2D) += renesas/rts7751r2d
machdir-$(CONFIG_SH_7751_SYSTEMH) += renesas/systemh
machdir-$(CONFIG_SH_EDOSK7705) += renesas/edosk7705
machdir-$(CONFIG_SH_HIGHLANDER) += renesas/r7780rp
+machdir-$(CONFIG_SH_SDK7780) += renesas/sdk7780
machdir-$(CONFIG_SH_7710VOIPGW) += renesas/sh7710voipgw
machdir-$(CONFIG_SH_X3PROTO) += renesas/x3proto
machdir-$(CONFIG_SH_SH4202_MICRODEV) += superh/microdev
@@ -127,6 +127,7 @@ machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) += se/7206
machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) += se/7619
machdir-$(CONFIG_SH_LBOX_RE2) += lboxre2
machdir-$(CONFIG_SH_MAGIC_PANEL_R2) += magicpanelr2
+machdir-$(CONFIG_SH_CAYMAN) += cayman
incdir-y := $(notdir $(machdir-y))
@@ -137,22 +138,22 @@ endif
# Companion chips
core-$(CONFIG_HD6446X_SERIES) += arch/sh/cchips/hd6446x/
-core-$(CONFIG_MFD_SM501) += arch/sh/cchips/voyagergx/
cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2
cpuincdir-$(CONFIG_CPU_SH2A) := cpu-sh2a
cpuincdir-$(CONFIG_CPU_SH3) := cpu-sh3
cpuincdir-$(CONFIG_CPU_SH4) := cpu-sh4
+cpuincdir-$(CONFIG_CPU_SH5) := cpu-sh5
-libs-y := arch/sh/lib/ $(libs-y) $(LIBGCC)
+libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y)
+libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y)
+libs-y += $(LIBGCC)
drivers-y += arch/sh/drivers/
drivers-$(CONFIG_OPROFILE) += arch/sh/oprofile/
boot := arch/sh/boot
-CPPFLAGS_vmlinux.lds := -traditional
-
incdir-prefix := $(srctree)/include/asm-sh/
# Update machine arch and proc symlinks if something which affects
@@ -196,29 +197,61 @@ include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
done
@touch $@
-archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
-
PHONY += maketools FORCE
+
maketools: include/linux/version.h FORCE
$(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
-all: zImage
+all: $(KBUILD_IMAGE)
zImage uImage uImage.srec vmlinux.srec: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
compressed: zImage
+archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools \
+ arch/sh/lib64/syscalltab.h
+
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
-CLEAN_FILES += include/asm-sh/machtypes.h \
- include/asm-sh/cpu include/asm-sh/.cpu \
- include/asm-sh/mach include/asm-sh/.mach
-
define archhelp
@echo '* zImage - Compressed kernel image'
@echo ' vmlinux.srec - Create an ELF S-record'
@echo ' uImage - Create a bootable image for U-Boot'
@echo ' uImage.srec - Create an S-record for U-Boot'
endef
+
+define filechk_gen-syscalltab
+ (set -e; \
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+ echo " * This file was generated by arch/sh/Makefile"; \
+ echo " * Any changes will be reverted at build time."; \
+ echo " */"; \
+ echo ""; \
+ echo "#ifndef __SYSCALLTAB_H"; \
+ echo "#define __SYSCALLTAB_H"; \
+ echo ""; \
+ echo "#include <linux/kernel.h>"; \
+ echo ""; \
+ echo "struct syscall_info {"; \
+ echo " const char *name;"; \
+ echo "} syscall_info_table[] = {"; \
+ sed -e '/^.*\.long /!d;s// { "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
+ s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \
+ echo "};"; \
+ echo ""; \
+ echo "#define NUM_SYSCALL_INFO_ENTRIES ARRAY_SIZE(syscall_info_table)";\
+ echo ""; \
+ echo "#endif /* __SYSCALLTAB_H */" )
+endef
+
+arch/sh/lib64/syscalltab.h: arch/sh/kernel/syscalls_64.S
+ $(call filechk,gen-syscalltab)
+
+CLEAN_FILES += arch/sh/lib64/syscalltab.h \
+ include/asm-sh/machtypes.h \
+ include/asm-sh/cpu include/asm-sh/.cpu \
+ include/asm-sh/mach include/asm-sh/.mach
diff --git a/arch/sh/boards/cayman/Makefile b/arch/sh/boards/cayman/Makefile
new file mode 100644
index 000000000000..489a8f867368
--- /dev/null
+++ b/arch/sh/boards/cayman/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Hitachi Cayman specific parts of the kernel
+#
+obj-y := setup.o irq.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/cayman/irq.c b/arch/sh/boards/cayman/irq.c
new file mode 100644
index 000000000000..30ec7bebfaf1
--- /dev/null
+++ b/arch/sh/boards/cayman/irq.c
@@ -0,0 +1,197 @@
+/*
+ * arch/sh/mach-cayman/irq.c - SH-5 Cayman Interrupt Support
+ *
+ * This file handles the board specific parts of the Cayman interrupt system
+ *
+ * Copyright (C) 2002 Stuart Menefy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <asm/cpu/irq.h>
+#include <asm/page.h>
+
+/* Setup for the SMSC FDC37C935 / LAN91C100FD */
+#define SMSC_IRQ IRQ_IRL1
+
+/* Setup for PCI Bus 2, which transmits interrupts via the EPLD */
+#define PCI2_IRQ IRQ_IRL3
+
+unsigned long epld_virt;
+
+#define EPLD_BASE 0x04002000
+#define EPLD_STATUS_BASE (epld_virt + 0x10)
+#define EPLD_MASK_BASE (epld_virt + 0x20)
+
+/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto
+ the same SH-5 interrupt */
+
+static irqreturn_t cayman_interrupt_smsc(int irq, void *dev_id)
+{
+ printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n");
+ return IRQ_NONE;
+}
+
+static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id)
+{
+ printk(KERN_INFO "CAYMAN: spurious PCI interrupt, IRQ %d\n", irq);
+ return IRQ_NONE;
+}
+
+static struct irqaction cayman_action_smsc = {
+ .name = "Cayman SMSC Mux",
+ .handler = cayman_interrupt_smsc,
+ .flags = IRQF_DISABLED,
+};
+
+static struct irqaction cayman_action_pci2 = {
+ .name = "Cayman PCI2 Mux",
+ .handler = cayman_interrupt_pci2,
+ .flags = IRQF_DISABLED,
+};
+
+static void enable_cayman_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned long mask;
+ unsigned int reg;
+ unsigned char bit;
+
+ irq -= START_EXT_IRQS;
+ reg = EPLD_MASK_BASE + ((irq / 8) << 2);
+ bit = 1<<(irq % 8);
+ local_irq_save(flags);
+ mask = ctrl_inl(reg);
+ mask |= bit;
+ ctrl_outl(mask, reg);
+ local_irq_restore(flags);
+}
+
+void disable_cayman_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned long mask;
+ unsigned int reg;
+ unsigned char bit;
+
+ irq -= START_EXT_IRQS;
+ reg = EPLD_MASK_BASE + ((irq / 8) << 2);
+ bit = 1<<(irq % 8);
+ local_irq_save(flags);
+ mask = ctrl_inl(reg);
+ mask &= ~bit;
+ ctrl_outl(mask, reg);
+ local_irq_restore(flags);
+}
+
+static void ack_cayman_irq(unsigned int irq)
+{
+ disable_cayman_irq(irq);
+}
+
+static void end_cayman_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_cayman_irq(irq);
+}
+
+static unsigned int startup_cayman_irq(unsigned int irq)
+{
+ enable_cayman_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void shutdown_cayman_irq(unsigned int irq)
+{
+ disable_cayman_irq(irq);
+}
+
+struct hw_interrupt_type cayman_irq_type = {
+ .typename = "Cayman-IRQ",
+ .startup = startup_cayman_irq,
+ .shutdown = shutdown_cayman_irq,
+ .enable = enable_cayman_irq,
+ .disable = disable_cayman_irq,
+ .ack = ack_cayman_irq,
+ .end = end_cayman_irq,
+};
+
+int cayman_irq_demux(int evt)
+{
+ int irq = intc_evt_to_irq[evt];
+
+ if (irq == SMSC_IRQ) {
+ unsigned long status;
+ int i;
+
+ status = ctrl_inl(EPLD_STATUS_BASE) &
+ ctrl_inl(EPLD_MASK_BASE) & 0xff;
+ if (status == 0) {
+ irq = -1;
+ } else {
+ for (i=0; i<8; i++) {
+ if (status & (1<<i))
+ break;
+ }
+ irq = START_EXT_IRQS + i;
+ }
+ }
+
+ if (irq == PCI2_IRQ) {
+ unsigned long status;
+ int i;
+
+ status = ctrl_inl(EPLD_STATUS_BASE + 3 * sizeof(u32)) &
+ ctrl_inl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff;
+ if (status == 0) {
+ irq = -1;
+ } else {
+ for (i=0; i<8; i++) {
+ if (status & (1<<i))
+ break;
+ }
+ irq = START_EXT_IRQS + (3 * 8) + i;
+ }
+ }
+
+ return irq;
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+int cayman_irq_describe(char* p, int irq)
+{
+ if (irq < NR_INTC_IRQS) {
+ return intc_irq_describe(p, irq);
+ } else if (irq < NR_INTC_IRQS + 8) {
+ return sprintf(p, "(SMSC %d)", irq - NR_INTC_IRQS);
+ } else if ((irq >= NR_INTC_IRQS + 24) && (irq < NR_INTC_IRQS + 32)) {
+ return sprintf(p, "(PCI2 %d)", irq - (NR_INTC_IRQS + 24));
+ }
+
+ return 0;
+}
+#endif
+
+void init_cayman_irq(void)
+{
+ int i;
+
+ epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD");
+ if (!epld_virt) {
+ printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");
+ return;
+ }
+
+ for (i=0; i<NR_EXT_IRQS; i++) {
+ irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
+ }
+
+ /* Setup the SMSC interrupt */
+ setup_irq(SMSC_IRQ, &cayman_action_smsc);
+ setup_irq(PCI2_IRQ, &cayman_action_pci2);
+}
diff --git a/arch/sh/boards/cayman/led.c b/arch/sh/boards/cayman/led.c
new file mode 100644
index 000000000000..a808eac4ecd6
--- /dev/null
+++ b/arch/sh/boards/cayman/led.c
@@ -0,0 +1,51 @@
+/*
+ * arch/sh/boards/cayman/led.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Flash the LEDs
+ */
+#include <asm/io.h>
+
+/*
+** It is supposed these functions to be used for a low level
+** debugging (via Cayman LEDs), hence to be available as soon
+** as possible.
+** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped
+** (this happen when IRQ are initialized... quite late).
+** These triky dependencies should be removed. Temporary, it
+** may be enough to NOP until EPLD is mapped.
+*/
+
+extern unsigned long epld_virt;
+
+#define LED_ADDR (epld_virt + 0x008)
+#define HDSP2534_ADDR (epld_virt + 0x100)
+
+void mach_led(int position, int value)
+{
+ if (!epld_virt)
+ return;
+
+ if (value)
+ ctrl_outl(0, LED_ADDR);
+ else
+ ctrl_outl(1, LED_ADDR);
+
+}
+
+void mach_alphanum(int position, unsigned char value)
+{
+ if (!epld_virt)
+ return;
+
+ ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2));
+}
+
+void mach_alphanum_brightness(int setting)
+{
+ ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0);
+}
diff --git a/arch/sh/boards/cayman/setup.c b/arch/sh/boards/cayman/setup.c
new file mode 100644
index 000000000000..8c9fa472d8f5
--- /dev/null
+++ b/arch/sh/boards/cayman/setup.c
@@ -0,0 +1,187 @@
+/*
+ * arch/sh/mach-cayman/setup.c
+ *
+ * SH5 Cayman support
+ *
+ * Copyright (C) 2002 David J. Mckay & Benedict Gaster
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <asm/cpu/irq.h>
+
+/*
+ * Platform Dependent Interrupt Priorities.
+ */
+
+/* Using defaults defined in irq.h */
+#define RES NO_PRIORITY /* Disabled */
+#define IR0 IRL0_PRIORITY /* IRLs */
+#define IR1 IRL1_PRIORITY
+#define IR2 IRL2_PRIORITY
+#define IR3 IRL3_PRIORITY
+#define PCA INTA_PRIORITY /* PCI Ints */
+#define PCB INTB_PRIORITY
+#define PCC INTC_PRIORITY
+#define PCD INTD_PRIORITY
+#define SER TOP_PRIORITY
+#define ERR TOP_PRIORITY
+#define PW0 TOP_PRIORITY
+#define PW1 TOP_PRIORITY
+#define PW2 TOP_PRIORITY
+#define PW3 TOP_PRIORITY
+#define DM0 NO_PRIORITY /* DMA Ints */
+#define DM1 NO_PRIORITY
+#define DM2 NO_PRIORITY
+#define DM3 NO_PRIORITY
+#define DAE NO_PRIORITY
+#define TU0 TIMER_PRIORITY /* TMU Ints */
+#define TU1 NO_PRIORITY
+#define TU2 NO_PRIORITY
+#define TI2 NO_PRIORITY
+#define ATI NO_PRIORITY /* RTC Ints */
+#define PRI NO_PRIORITY
+#define CUI RTC_PRIORITY
+#define ERI SCIF_PRIORITY /* SCIF Ints */
+#define RXI SCIF_PRIORITY
+#define BRI SCIF_PRIORITY
+#define TXI SCIF_PRIORITY
+#define ITI TOP_PRIORITY /* WDT Ints */
+
+/* Setup for the SMSC FDC37C935 */
+#define SMSC_SUPERIO_BASE 0x04000000
+#define SMSC_CONFIG_PORT_ADDR 0x3f0
+#define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR
+#define SMSC_DATA_PORT_ADDR 0x3f1
+
+#define SMSC_ENTER_CONFIG_KEY 0x55
+#define SMSC_EXIT_CONFIG_KEY 0xaa
+
+#define SMCS_LOGICAL_DEV_INDEX 0x07
+#define SMSC_DEVICE_ID_INDEX 0x20
+#define SMSC_DEVICE_REV_INDEX 0x21
+#define SMSC_ACTIVATE_INDEX 0x30
+#define SMSC_PRIMARY_BASE_INDEX 0x60
+#define SMSC_SECONDARY_BASE_INDEX 0x62
+#define SMSC_PRIMARY_INT_INDEX 0x70
+#define SMSC_SECONDARY_INT_INDEX 0x72
+
+#define SMSC_IDE1_DEVICE 1
+#define SMSC_KEYBOARD_DEVICE 7
+#define SMSC_CONFIG_REGISTERS 8
+
+#define SMSC_SUPERIO_READ_INDEXED(index) ({ \
+ outb((index), SMSC_INDEX_PORT_ADDR); \
+ inb(SMSC_DATA_PORT_ADDR); })
+#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \
+ outb((index), SMSC_INDEX_PORT_ADDR); \
+ outb((val), SMSC_DATA_PORT_ADDR); })
+
+#define IDE1_PRIMARY_BASE 0x01f0
+#define IDE1_SECONDARY_BASE 0x03f6
+
+unsigned long smsc_superio_virt;
+
+int platform_int_priority[NR_INTC_IRQS] = {
+ IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD, /* IRQ 0- 7 */
+ RES, RES, RES, RES, SER, ERR, PW3, PW2, /* IRQ 8-15 */
+ PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES, /* IRQ 16-23 */
+ RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 24-31 */
+ TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI, /* IRQ 32-39 */
+ RXI, BRI, TXI, RES, RES, RES, RES, RES, /* IRQ 40-47 */
+ RES, RES, RES, RES, RES, RES, RES, RES, /* IRQ 48-55 */
+ RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */
+};
+
+static int __init smsc_superio_setup(void)
+{
+ unsigned char devid, devrev;
+
+ smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO");
+ if (!smsc_superio_virt) {
+ panic("Unable to remap SMSC SuperIO\n");
+ }
+
+ /* Initially the chip is in run state */
+ /* Put it into configuration state */
+ outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+ outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+ /* Read device ID info */
+ devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+ devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+ printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev);
+
+ /* Select the keyboard device */
+ SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+
+ /* enable it */
+ SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+
+ /* Select the interrupts */
+ /* On a PC keyboard is IRQ1, mouse is IRQ12 */
+ SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
+ SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
+
+#ifdef CONFIG_IDE
+ /*
+ * Only IDE1 exists on the Cayman
+ */
+
+ /* Power it on */
+ SMSC_SUPERIO_WRITE_INDEXED(1 << SMSC_IDE1_DEVICE, 0x22);
+
+ SMSC_SUPERIO_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+
+ SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE >> 8,
+ SMSC_PRIMARY_BASE_INDEX + 0);
+ SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE & 0xff,
+ SMSC_PRIMARY_BASE_INDEX + 1);
+
+ SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE >> 8,
+ SMSC_SECONDARY_BASE_INDEX + 0);
+ SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE & 0xff,
+ SMSC_SECONDARY_BASE_INDEX + 1);
+
+ SMSC_SUPERIO_WRITE_INDEXED(14, SMSC_PRIMARY_INT_INDEX);
+
+ SMSC_SUPERIO_WRITE_INDEXED(SMSC_CONFIG_REGISTERS,
+ SMCS_LOGICAL_DEV_INDEX);
+
+ SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
+ SMSC_SUPERIO_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
+ SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
+ SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
+#endif
+
+ /* Exit the configuration state */
+ outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+ return 0;
+}
+__initcall(smsc_superio_setup);
+
+static void __iomem *cayman_ioport_map(unsigned long port, unsigned int len)
+{
+ if (port < 0x400) {
+ extern unsigned long smsc_superio_virt;
+ return (void __iomem *)((port << 2) | smsc_superio_virt);
+ }
+
+ return (void __iomem *)port;
+}
+
+extern void init_cayman_irq(void);
+
+static struct sh_machine_vector mv_cayman __initmv = {
+ .mv_name = "Hitachi Cayman",
+ .mv_nr_irqs = 64,
+ .mv_ioport_map = cayman_ioport_map,
+ .mv_init_irq = init_cayman_irq,
+};
diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c
index 5bf01f86c20c..9d0673a9092a 100644
--- a/arch/sh/boards/dreamcast/irq.c
+++ b/arch/sh/boards/dreamcast/irq.c
@@ -136,7 +136,7 @@ int systemasic_irq_demux(int irq)
emr = EMR_BASE + (level << 4) + (level << 2);
esr = ESR_BASE + (level << 2);
- /* Mask the ESR to filter any spurious, unwanted interrtupts */
+ /* Mask the ESR to filter any spurious, unwanted interrupts */
status = inl(esr);
status &= inl(emr);
diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
index 8799df6e866a..2581c8cd5df7 100644
--- a/arch/sh/boards/dreamcast/setup.c
+++ b/arch/sh/boards/dreamcast/setup.c
@@ -33,9 +33,6 @@ extern void aica_time_init(void);
extern int gapspci_init(void);
extern int systemasic_irq_demux(int);
-void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
-int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
-
static void __init dreamcast_setup(char **cmdline_p)
{
int i;
@@ -64,9 +61,4 @@ static struct sh_machine_vector mv_dreamcast __initmv = {
.mv_name = "Sega Dreamcast",
.mv_setup = dreamcast_setup,
.mv_irq_demux = systemasic_irq_demux,
-
-#ifdef CONFIG_PCI
- .mv_consistent_alloc = dreamcast_consistent_alloc,
- .mv_consistent_free = dreamcast_consistent_free,
-#endif
};
diff --git a/arch/sh/boards/landisk/gio.c b/arch/sh/boards/landisk/gio.c
index a37643d002b2..17025080db35 100644
--- a/arch/sh/boards/landisk/gio.c
+++ b/arch/sh/boards/landisk/gio.c
@@ -121,7 +121,7 @@ static int gio_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-static struct file_operations gio_fops = {
+static const struct file_operations gio_fops = {
.owner = THIS_MODULE,
.open = gio_open, /* open */
.release = gio_close, /* release */
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Kconfig b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
deleted file mode 100644
index 1743be477be5..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-if SH_HS7751RVOIP
-
-menu "HS7751RVoIP options"
-
-config HS7751RVOIP_CODEC
- bool "Support VoIP Codec section"
- help
- Selecting this option will support CODEC section.
-
-endmenu
-
-endif
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile
deleted file mode 100644
index e626377c55ee..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the HS7751RVoIP specific parts of the kernel
-#
-
-obj-y := setup.o io.o irq.o
-
-obj-$(CONFIG_PCI) += pci.o
-
diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c
deleted file mode 100644
index bb9aa0d62852..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/io.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/hs7751rvoip/io.c
- *
- * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Renesas Technology sales HS7751RVoIP
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_hs7751rvoip.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/hs7751rvoip.h>
-#include <asm/addrspace.h>
-
-extern void *area6_io8_base; /* Area 6 8bit I/O Base address */
-extern void *area5_io16_base; /* Area 5 16bit I/O Base address */
-
-/*
- * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
- * of the 7751R processor, and has a SuperIO accessible via the PCI.
- * The board also includes a PCMCIA controller on its memory bus,
- * like the other Solution Engine boards.
- */
-
-#define CODEC_IO_BASE 0x1000
-#define CODEC_IOMAP(a) ((unsigned long)area6_io8_base + ((a) - CODEC_IO_BASE))
-
-static inline unsigned long port2adr(unsigned int port)
-{
- if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
- if (port == 0x3f6)
- return ((unsigned long)area5_io16_base + 0x0c);
- else
- return ((unsigned long)area5_io16_base + 0x800 +
- ((port-0x1f0) << 1));
- else
- maybebadio((unsigned long)port);
- return port;
-}
-
-/* The 7751R HS7751RVoIP seems to have everything hooked */
-/* up pretty normally (nothing on high-bytes only...) so this */
-/* shouldn't be needed */
-static inline int shifted_port(unsigned long port)
-{
- /* For IDE registers, value is not shifted */
- if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
- return 0;
- else
- return 1;
-}
-
-#if defined(CONFIG_HS7751RVOIP_CODEC)
-#define codec_port(port) \
- ((CODEC_IO_BASE <= (port)) && ((port) < (CODEC_IO_BASE + 0x20)))
-#else
-#define codec_port(port) (0)
-#endif
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used w/o translation for
- * compatibility.
- */
-unsigned char hs7751rvoip_inb(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inb(port);
- else if (codec_port(port))
- return ctrl_inb(CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port))
- return ctrl_inb(pci_ioaddr(port));
- else
- return ctrl_inw(port2adr(port)) & 0xff;
-}
-
-unsigned char hs7751rvoip_inb_p(unsigned long port)
-{
- unsigned char v;
-
- if (PXSEG(port))
- v = ctrl_inb(port);
- else if (codec_port(port))
- v = ctrl_inb(CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port))
- v = ctrl_inb(pci_ioaddr(port));
- else
- v = ctrl_inw(port2adr(port)) & 0xff;
- ctrl_delay();
- return v;
-}
-
-unsigned short hs7751rvoip_inw(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inw(port);
- else if (is_pci_ioaddr(port) || shifted_port(port))
- return ctrl_inw(pci_ioaddr(port));
- else
- maybebadio(port);
- return 0;
-}
-
-unsigned int hs7751rvoip_inl(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inl(port);
- else if (is_pci_ioaddr(port) || shifted_port(port))
- return ctrl_inl(pci_ioaddr(port));
- else
- maybebadio(port);
- return 0;
-}
-
-void hs7751rvoip_outb(unsigned char value, unsigned long port)
-{
-
- if (PXSEG(port))
- ctrl_outb(value, port);
- else if (codec_port(port))
- ctrl_outb(value, CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port))
- ctrl_outb(value, pci_ioaddr(port));
- else
- ctrl_outb(value, port2adr(port));
-}
-
-void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outb(value, port);
- else if (codec_port(port))
- ctrl_outb(value, CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port))
- ctrl_outb(value, pci_ioaddr(port));
- else
- ctrl_outw(value, port2adr(port));
-
- ctrl_delay();
-}
-
-void hs7751rvoip_outw(unsigned short value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outw(value, port);
- else if (is_pci_ioaddr(port) || shifted_port(port))
- ctrl_outw(value, pci_ioaddr(port));
- else
- maybebadio(port);
-}
-
-void hs7751rvoip_outl(unsigned int value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outl(value, port);
- else if (is_pci_ioaddr(port) || shifted_port(port))
- ctrl_outl(value, pci_ioaddr(port));
- else
- maybebadio(port);
-}
-
-void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
-{
- u8 *buf = addr;
-
- if (PXSEG(port))
- while (count--)
- *buf++ = ctrl_inb(port);
- else if (codec_port(port))
- while (count--)
- *buf++ = ctrl_inb(CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port)) {
- volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
-
- while (count--)
- *buf++ = *bp;
- } else {
- volatile u16 *p = (volatile u16 *)port2adr(port);
-
- while (count--)
- *buf++ = *p & 0xff;
- }
-}
-
-void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
-{
- volatile u16 *p;
- u16 *buf = addr;
-
- if (PXSEG(port))
- p = (volatile u16 *)port;
- else if (is_pci_ioaddr(port) || shifted_port(port))
- p = (volatile u16 *)pci_ioaddr(port);
- else
- p = (volatile u16 *)port2adr(port);
- while (count--)
- *buf++ = *p;
-}
-
-void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
-{
-
- if (is_pci_ioaddr(port) || shifted_port(port)) {
- volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
- u32 *buf = addr;
-
- while (count--)
- *buf++ = *p;
- } else
- maybebadio(port);
-}
-
-void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
-{
- const u8 *buf = addr;
-
- if (PXSEG(port))
- while (count--)
- ctrl_outb(*buf++, port);
- else if (codec_port(port))
- while (count--)
- ctrl_outb(*buf++, CODEC_IOMAP(port));
- else if (is_pci_ioaddr(port) || shifted_port(port)) {
- volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
-
- while (count--)
- *bp = *buf++;
- } else {
- volatile u16 *p = (volatile u16 *)port2adr(port);
-
- while (count--)
- *p = *buf++;
- }
-}
-
-void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
-{
- volatile u16 *p;
- const u16 *buf = addr;
-
- if (PXSEG(port))
- p = (volatile u16 *)port;
- else if (is_pci_ioaddr(port) || shifted_port(port))
- p = (volatile u16 *)pci_ioaddr(port);
- else
- p = (volatile u16 *)port2adr(port);
-
- while (count--)
- *p = *buf++;
-}
-
-void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
-{
- const u32 *buf = addr;
-
- if (is_pci_ioaddr(port) || shifted_port(port)) {
- volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
-
- while (count--)
- *p = *buf++;
- } else
- maybebadio(port);
-}
-
-void __iomem *hs7751rvoip_ioport_map(unsigned long port, unsigned int size)
-{
- if (PXSEG(port))
- return (void __iomem *)port;
- else if (unlikely(codec_port(port) && (size == 1)))
- return (void __iomem *)CODEC_IOMAP(port);
- else if (is_pci_ioaddr(port))
- return (void __iomem *)pci_ioaddr(port);
-
- return (void __iomem *)port2adr(port);
-}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c
deleted file mode 100644
index e55c6686b21f..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/irq.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/hs7751rvoip/irq.c
- *
- * Copyright (C) 2000 Kazumoto Kojima
- *
- * Renesas Technology Sales HS7751RVoIP Support.
- *
- * Modified for HS7751RVoIP by
- * Atom Create Engineering Co., Ltd. 2002.
- * Lineo uSolutions, Inc. 2003.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/hs7751rvoip.h>
-
-static int mask_pos[] = {8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7};
-
-static void enable_hs7751rvoip_irq(unsigned int irq);
-static void disable_hs7751rvoip_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_hs7751rvoip_irq disable_hs7751rvoip_irq
-
-static void ack_hs7751rvoip_irq(unsigned int irq);
-static void end_hs7751rvoip_irq(unsigned int irq);
-
-static unsigned int startup_hs7751rvoip_irq(unsigned int irq)
-{
- enable_hs7751rvoip_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void disable_hs7751rvoip_irq(unsigned int irq)
-{
- unsigned short val;
- unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
-
- /* Set the priority in IPR to 0 */
- val = ctrl_inw(IRLCNTR3);
- val &= mask;
- ctrl_outw(val, IRLCNTR3);
-}
-
-static void enable_hs7751rvoip_irq(unsigned int irq)
-{
- unsigned short val;
- unsigned short value = (0x0001 << mask_pos[irq]);
-
- /* Set priority in IPR back to original value */
- val = ctrl_inw(IRLCNTR3);
- val |= value;
- ctrl_outw(val, IRLCNTR3);
-}
-
-static void ack_hs7751rvoip_irq(unsigned int irq)
-{
- disable_hs7751rvoip_irq(irq);
-}
-
-static void end_hs7751rvoip_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_hs7751rvoip_irq(irq);
-}
-
-static struct hw_interrupt_type hs7751rvoip_irq_type = {
- .typename = "HS7751RVoIP IRQ",
- .startup = startup_hs7751rvoip_irq,
- .shutdown = shutdown_hs7751rvoip_irq,
- .enable = enable_hs7751rvoip_irq,
- .disable = disable_hs7751rvoip_irq,
- .ack = ack_hs7751rvoip_irq,
- .end = end_hs7751rvoip_irq,
-};
-
-static void make_hs7751rvoip_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- irq_desc[irq].chip = &hs7751rvoip_irq_type;
- disable_hs7751rvoip_irq(irq);
-}
-
-/*
- * Initialize IRQ setting
- */
-void __init init_hs7751rvoip_IRQ(void)
-{
- int i;
-
- /* IRL0=ON HOOK1
- * IRL1=OFF HOOK1
- * IRL2=ON HOOK2
- * IRL3=OFF HOOK2
- * IRL4=Ringing Detection
- * IRL5=CODEC
- * IRL6=Ethernet
- * IRL7=Ethernet Hub
- * IRL8=USB Communication
- * IRL9=USB Connection
- * IRL10=USB DMA
- * IRL11=CF Card
- * IRL12=PCMCIA
- * IRL13=PCI Slot
- */
- ctrl_outw(0x9876, IRLCNTR1);
- ctrl_outw(0xdcba, IRLCNTR2);
- ctrl_outw(0x0050, IRLCNTR4);
- ctrl_outw(0x4321, IRLCNTR5);
-
- for (i=0; i<14; i++)
- make_hs7751rvoip_irq(i);
-}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c
deleted file mode 100644
index 1c0ddee30d21..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/pci.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/hs7751rvoip/pci.c
- *
- * Author: Ian DaSilva (idasilva@mvista.com)
- *
- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * PCI initialization for the Renesas SH7751R HS7751RVoIP board
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include "../../../drivers/pci/pci-sh7751.h"
-#include <asm/hs7751rvoip/hs7751rvoip.h>
-
-#define PCIMCR_MRSET_OFF 0xBFFFFFFF
-#define PCIMCR_RFSH_OFF 0xFFFFFFFB
-
-/*
- * Only long word accesses of the PCIC's internal local registers and the
- * configuration registers from the CPU is supported.
- */
-#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
-#define PCIC_READ(x) readl(PCI_REG(x))
-
-/*
- * Description: This function sets up and initializes the pcic, sets
- * up the BARS, maps the DRAM into the address space etc, etc.
- */
-int __init pcibios_init_platform(void)
-{
- unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
- unsigned short bcr2, bcr3;
-
- /*
- * Initialize the slave bus controller on the pcic. The values used
- * here should not be hardcoded, but they should be taken from the bsc
- * on the processor, to make this function as generic as possible.
- * (i.e. Another sbc may usr different SDRAM timing settings -- in order
- * for the pcic to work, its settings need to be exactly the same.)
- */
- bcr1 = (*(volatile unsigned long *)(SH7751_BCR1));
- bcr2 = (*(volatile unsigned short *)(SH7751_BCR2));
- bcr3 = (*(volatile unsigned short *)(SH7751_BCR3));
- wcr1 = (*(volatile unsigned long *)(SH7751_WCR1));
- wcr2 = (*(volatile unsigned long *)(SH7751_WCR2));
- wcr3 = (*(volatile unsigned long *)(SH7751_WCR3));
- mcr = (*(volatile unsigned long *)(SH7751_MCR));
-
- bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */
- (*(volatile unsigned long *)(SH7751_BCR1)) = bcr1;
-
- bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
- PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */
- PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */
- PCIC_WRITE(SH7751_PCIBCR3, bcr3); /* PCIC BCR3 */
- PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */
- PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */
- PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */
- mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
- PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */
-
- /* Enable all interrupts, so we know what to fix */
- PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
- PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
-
- /* Set up standard PCI config registers */
- PCIC_WRITE(SH7751_PCICONF1, 0xFB900047); /* Bus Master, Mem & I/O access */
- PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
- PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */
- PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */
- PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */
- PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
- PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */
- PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */
- PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */
- PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */
-
- /* Now turn it on... */
- PCIC_WRITE(SH7751_PCICR, 0xa5000001);
-
- /*
- * Set PCIMBR and PCIIOBR here, assuming a single window
- * (16M MEM, 256K IO) is enough. If a larger space is
- * needed, the readx/writex and inx/outx functions will
- * have to do more (e.g. setting registers for each call).
- */
-
- /*
- * Set the MBR so PCI address is one-to-one with window,
- * meaning all calls go straight through... use ifdef to
- * catch erroneous assumption.
- */
- BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
-
- PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
-
- /* Set IOBR for window containing area specified in pci.h */
- PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));
-
- /* All done, may as well say so... */
- printk("SH7751R PCI: Finished initialization of the PCI controller\n");
-
- return 1;
-}
-
-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
-{
- switch (slot) {
- case 0: return IRQ_PCISLOT; /* PCI Extend slot */
- case 1: return IRQ_PCMCIA; /* PCI Cardbus Bridge */
- case 2: return IRQ_PCIETH; /* Realtek Ethernet controller */
- case 3: return IRQ_PCIHUB; /* Realtek Ethernet Hub controller */
- default:
- printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
- return -1;
- }
-}
-
-static struct resource sh7751_io_resource = {
- .name = "SH7751_IO",
- .start = 0x4000,
- .end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
- .flags = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
- .name = "SH7751_mem",
- .start = SH7751_PCI_MEMORY_BASE,
- .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
- .flags = IORESOURCE_MEM
-};
-
-extern struct pci_ops sh7751_pci_ops;
-
-struct pci_channel board_pci_channels[] = {
- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
- { NULL, NULL, NULL, 0, 0 },
-};
-EXPORT_SYMBOL(board_pci_channels);
diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
deleted file mode 100644
index c05625975f2c..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/setup.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Renesas Technology Sales HS7751RVoIP Support.
- *
- * Copyright (C) 2000 Kazumoto Kojima
- *
- * Modified for HS7751RVoIP by
- * Atom Create Engineering Co., Ltd. 2002.
- * Lineo uSolutions, Inc. 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/mm.h>
-#include <linux/pm.h>
-#include <asm/hs7751rvoip.h>
-#include <asm/io.h>
-#include <asm/machvec.h>
-
-static void hs7751rvoip_power_off(void)
-{
- ctrl_outw(ctrl_inw(PA_OUTPORTR) & 0xffdf, PA_OUTPORTR);
-}
-
-void *area5_io8_base;
-void *area6_io8_base;
-void *area5_io16_base;
-void *area6_io16_base;
-
-static int __init hs7751rvoip_cf_init(void)
-{
- pgprot_t prot;
- unsigned long paddrbase;
-
- /* open I/O area window */
- paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800));
- prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16);
- area5_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
- if (!area5_io16_base) {
- printk("allocate_cf_area : can't open CF I/O window!\n");
- return -ENOMEM;
- }
-
- /* XXX : do we need attribute and common-memory area also? */
-
- paddrbase = virt_to_phys((void *)PA_AREA6_IO);
-#if defined(CONFIG_HS7751RVOIP_CODEC)
- prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8);
-#else
- prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8);
-#endif
- area6_io8_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
- if (!area6_io8_base) {
- printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n");
- return -ENOMEM;
- }
- prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
- area6_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
- if (!area6_io16_base) {
- printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-device_initcall(hs7751rvoip_cf_init);
-
-/*
- * Initialize the board
- */
-static void __init hs7751rvoip_setup(char **cmdline_p)
-{
- ctrl_outb(0xf0, PA_OUTPORTR);
- pm_power_off = hs7751rvoip_power_off;
-
- printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
-}
-
-static struct sh_machine_vector mv_hs7751rvoip __initmv = {
- .mv_name = "HS7751RVoIP",
- .mv_setup = hs7751rvoip_setup,
- .mv_nr_irqs = 72,
-
- .mv_inb = hs7751rvoip_inb,
- .mv_inw = hs7751rvoip_inw,
- .mv_inl = hs7751rvoip_inl,
- .mv_outb = hs7751rvoip_outb,
- .mv_outw = hs7751rvoip_outw,
- .mv_outl = hs7751rvoip_outl,
-
- .mv_inb_p = hs7751rvoip_inb_p,
- .mv_inw_p = hs7751rvoip_inw,
- .mv_inl_p = hs7751rvoip_inl,
- .mv_outb_p = hs7751rvoip_outb_p,
- .mv_outw_p = hs7751rvoip_outw,
- .mv_outl_p = hs7751rvoip_outl,
-
- .mv_insb = hs7751rvoip_insb,
- .mv_insw = hs7751rvoip_insw,
- .mv_insl = hs7751rvoip_insl,
- .mv_outsb = hs7751rvoip_outsb,
- .mv_outsw = hs7751rvoip_outsw,
- .mv_outsl = hs7751rvoip_outsl,
-
- .mv_init_irq = init_hs7751rvoip_IRQ,
- .mv_ioport_map = hs7751rvoip_ioport_map,
-};
diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
index dd26182fbf58..20a10080b11f 100644
--- a/arch/sh/boards/renesas/r7780rp/Makefile
+++ b/arch/sh/boards/renesas/r7780rp/Makefile
@@ -3,7 +3,7 @@
#
irqinit-$(CONFIG_SH_R7780MP) := irq-r7780mp.o
irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o
-irqinit-$(CONFIG_SH_R7780RP) := irq-r7780rp.o irq.o
+irqinit-$(CONFIG_SH_R7780RP) := irq-r7780rp.o
obj-y := setup.o $(irqinit-y)
ifneq ($(CONFIG_SH_R7785RP),y)
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
index 59b47fe061f9..1f8f073f27be 100644
--- a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
@@ -47,7 +47,7 @@ static unsigned char irl2irq[HL_NR_IRL] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors,
- NULL, NULL, mask_registers, NULL, NULL);
+ NULL, mask_registers, NULL, NULL);
unsigned char * __init highlander_init_irq_r7780mp(void)
{
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
index fa4a534cade9..bd34048ed0e1 100644
--- a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
@@ -3,21 +3,65 @@
*
* Copyright (C) 2002 Atom Create Engineering Co., Ltd.
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2008 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/io.h>
#include <asm/r7780rp.h>
+enum {
+ UNUSED = 0,
+
+ /* board specific interrupt sources */
+
+ AX88796, /* Ethernet controller */
+ PSW, /* Push Switch */
+ CF, /* Compact Flash */
+
+ PCI_A,
+ PCI_B,
+ PCI_C,
+ PCI_D,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(PCI_A, 65), /* dirty: overwrite cpu vectors for pci */
+ INTC_IRQ(PCI_B, 66),
+ INTC_IRQ(PCI_C, 67),
+ INTC_IRQ(PCI_D, 68),
+ INTC_IRQ(CF, IRQ_CF),
+ INTC_IRQ(PSW, IRQ_PSW),
+ INTC_IRQ(AX88796, IRQ_AX88796),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xa5000000, 0, 16, /* IRLMSK */
+ { PCI_A, PCI_B, PCI_C, PCI_D, CF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, PSW, AX88796 } },
+};
+
+static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+ 65, 66, 67, 68,
+ IRQ_CF, 0, 0, 0,
+ 0, 0, 0, 0,
+ IRQ_AX88796, IRQ_PSW
+};
+
+static DECLARE_INTC_DESC(intc_desc, "r7780rp", vectors,
+ NULL, mask_registers, NULL, NULL);
+
unsigned char * __init highlander_init_irq_r7780rp(void)
{
- int i;
-
- for (i = 0; i < 15; i++)
- make_r7780rp_irq(i);
+ if (ctrl_inw(0xa5000600)) {
+ printk(KERN_INFO "Using r7780rp interrupt controller.\n");
+ register_intc_controller(&intc_desc);
+ return irl2irq;
+ }
return NULL;
}
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
index b2c6a84673bd..bf7ec107fbc6 100644
--- a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
@@ -2,7 +2,7 @@
* Renesas Solutions Highlander R7785RP Support.
*
* Copyright (C) 2002 Atom Create Engineering Co., Ltd.
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006 - 2008 Paul Mundt
* Copyright (C) 2007 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -17,31 +17,52 @@
enum {
UNUSED = 0,
- /* board specific interrupt sources */
- AX88796, /* Ethernet controller */
- CF, /* Compact Flash */
+ /* FPGA specific interrupt sources */
+ CF, /* Compact Flash */
+ SMBUS, /* SMBUS */
+ TP, /* Touch panel */
+ RTC, /* RTC Alarm */
+ TH_ALERT, /* Temperature sensor */
+ AX88796, /* Ethernet controller */
+
+ /* external bus connector */
+ EXT0, EXT1, EXT2, EXT3, EXT4, EXT5, EXT6, EXT7,
};
static struct intc_vect vectors[] __initdata = {
INTC_IRQ(CF, IRQ_CF),
+ INTC_IRQ(SMBUS, IRQ_SMBUS),
+ INTC_IRQ(TP, IRQ_TP),
+ INTC_IRQ(RTC, IRQ_RTC),
+ INTC_IRQ(TH_ALERT, IRQ_TH_ALERT),
+
+ INTC_IRQ(EXT0, IRQ_EXT0), INTC_IRQ(EXT1, IRQ_EXT1),
+ INTC_IRQ(EXT2, IRQ_EXT2), INTC_IRQ(EXT3, IRQ_EXT3),
+
+ INTC_IRQ(EXT4, IRQ_EXT4), INTC_IRQ(EXT5, IRQ_EXT5),
+ INTC_IRQ(EXT6, IRQ_EXT6), INTC_IRQ(EXT7, IRQ_EXT7),
+
INTC_IRQ(AX88796, IRQ_AX88796),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4000010, 0, 16, /* IRLMCR1 */
- { 0, 0, 0, 0, CF, AX88796, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 0, 0, 0, 0, CF, AX88796, SMBUS, TP,
+ RTC, 0, TH_ALERT, 0, 0, 0, 0, 0 } },
+ { 0xa4000012, 0, 16, /* IRLMCR2 */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ EXT7, EXT6, EXT5, EXT4, EXT3, EXT2, EXT1, EXT0 } },
};
static unsigned char irl2irq[HL_NR_IRL] __initdata = {
- 0, IRQ_CF, 0, 0,
- 0, 0, 0, 0,
- 0, 0, IRQ_AX88796, 0,
- 0, 0, 0,
+ 0, IRQ_CF, IRQ_EXT4, IRQ_EXT5,
+ IRQ_EXT6, IRQ_EXT7, IRQ_SMBUS, IRQ_TP,
+ IRQ_RTC, IRQ_TH_ALERT, IRQ_AX88796, IRQ_EXT0,
+ IRQ_EXT1, IRQ_EXT2, IRQ_EXT3,
};
static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors,
- NULL, NULL, mask_registers, NULL, NULL);
+ NULL, mask_registers, NULL, NULL);
unsigned char * __init highlander_init_irq_r7785rp(void)
{
@@ -58,7 +79,7 @@ unsigned char * __init highlander_init_irq_r7785rp(void)
ctrl_outw(0x7060, PA_IRLPRC); /* FPGA IRLC */
ctrl_outw(0x0000, PA_IRLPRD); /* FPGA IRLD */
ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */
- ctrl_outw(0x0000, PA_IRLPRF); /* FPGA IRLF */
+ ctrl_outw(0xdcba, PA_IRLPRF); /* FPGA IRLF */
register_intc_controller(&intc_desc);
return irl2irq;
diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
deleted file mode 100644
index e0b8eb52f376..000000000000
--- a/arch/sh/boards/renesas/r7780rp/irq.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Renesas Solutions Highlander R7780RP-1 Support.
- *
- * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
- * Copyright (C) 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <asm/r7780rp.h>
-
-#ifdef CONFIG_SH_R7780RP
-static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
-#elif defined(CONFIG_SH_R7780MP)
-static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
-#elif defined(CONFIG_SH_R7785RP)
-static int mask_pos[] = {2, 11, 2, 2, 2, 2, 9, 8, 7, 5, 10, 2, 2, 2, 2, 2};
-#endif
-
-static void enable_r7780rp_irq(unsigned int irq)
-{
- /* Set priority in IPR back to original value */
- ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
-}
-
-static void disable_r7780rp_irq(unsigned int irq)
-{
- /* Set the priority in IPR to 0 */
- ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
- IRLCNTR1);
-}
-
-static struct irq_chip r7780rp_irq_chip __read_mostly = {
- .name = "R7780RP",
- .mask = disable_r7780rp_irq,
- .unmask = enable_r7780rp_irq,
- .mask_ack = disable_r7780rp_irq,
-};
-
-void make_r7780rp_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &r7780rp_irq_chip,
- handle_level_irq, "level");
- enable_r7780rp_irq(irq);
-}
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index 0fdc0bc19145..a43b47726f54 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -179,9 +179,11 @@ static struct platform_device ax88796_device = {
static struct platform_device *r7780rp_devices[] __initdata = {
&r8a66597_usb_host_device,
&m66592_usb_peripheral_device,
- &cf_ide_device,
&heartbeat_device,
+#ifndef CONFIG_SH_R7780RP
+ &cf_ide_device,
&ax88796_device,
+#endif
};
static int __init r7780rp_devices_setup(void)
@@ -316,9 +318,9 @@ void __init highlander_init_irq(void)
break;
#endif
#ifdef CONFIG_SH_R7780RP
- highlander_init_irq_r7780rp();
- ucp = irl2irq;
- break;
+ ucp = highlander_init_irq_r7780rp();
+ if (ucp)
+ break;
#endif
} while (0);
diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
index 7cc2813adfe4..8e49f6e51247 100644
--- a/arch/sh/boards/renesas/rts7751r2d/irq.c
+++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
@@ -13,7 +13,6 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <asm/voyagergx.h>
#include <asm/rts7751r2d.h>
#define R2D_NR_IRL 13
@@ -71,7 +70,7 @@ static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1,
- NULL, NULL, mask_registers_r2d_1, NULL, NULL);
+ NULL, mask_registers_r2d_1, NULL, NULL);
#endif /* CONFIG_RTS7751R2D_1 */
@@ -109,7 +108,7 @@ static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus,
- NULL, NULL, mask_registers_r2d_plus, NULL, NULL);
+ NULL, mask_registers_r2d_plus, NULL, NULL);
#endif /* CONFIG_RTS7751R2D_PLUS */
@@ -153,7 +152,4 @@ void __init init_rts7751r2d_IRQ(void)
}
register_intc_controller(d);
-#ifdef CONFIG_MFD_SM501
- setup_voyagergx_irq();
-#endif
}
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 8125d20fdbd8..3452b072adde 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -13,34 +13,15 @@
#include <linux/pata_platform.h>
#include <linux/serial_8250.h>
#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
#include <linux/pm.h>
+#include <linux/fb.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
#include <asm/machvec.h>
#include <asm/rts7751r2d.h>
-#include <asm/voyagergx.h>
#include <asm/io.h>
-
-static void __init voyagergx_serial_init(void)
-{
- unsigned long val;
-
- /*
- * GPIO Control
- */
- val = readl((void __iomem *)GPIO_MUX_HIGH);
- val |= 0x00001fe0;
- writel(val, (void __iomem *)GPIO_MUX_HIGH);
-
- /*
- * Power Mode Gate
- */
- val = readl((void __iomem *)POWER_MODE0_GATE);
- val |= (POWER_MODE0_GATE_U0 | POWER_MODE0_GATE_U1);
- writel(val, (void __iomem *)POWER_MODE0_GATE);
-
- val = readl((void __iomem *)POWER_MODE1_GATE);
- val |= (POWER_MODE1_GATE_U0 | POWER_MODE1_GATE_U1);
- writel(val, (void __iomem *)POWER_MODE1_GATE);
-}
+#include <asm/spi.h>
static struct resource cf_ide_resources[] = {
[0] = {
@@ -75,6 +56,43 @@ static struct platform_device cf_ide_device = {
},
};
+static struct spi_board_info spi_bus[] = {
+ {
+ .modalias = "rtc-r9701",
+ .max_speed_hz = 1000000,
+ .mode = SPI_MODE_3,
+ },
+};
+
+static void r2d_chip_select(struct sh_spi_info *spi, int cs, int state)
+{
+ BUG_ON(cs != 0); /* Single Epson RTC-9701JE attached on CS0 */
+ ctrl_outw(state == BITBANG_CS_ACTIVE, PA_RTCCE);
+}
+
+static struct sh_spi_info spi_info = {
+ .num_chipselect = 1,
+ .chip_select = r2d_chip_select,
+};
+
+static struct resource spi_sh_sci_resources[] = {
+ {
+ .start = 0xffe00000,
+ .end = 0xffe0001f,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spi_sh_sci_device = {
+ .name = "spi_sh_sci",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(spi_sh_sci_resources),
+ .resource = spi_sh_sci_resources,
+ .dev = {
+ .platform_data = &spi_info,
+ },
+};
+
static struct resource heartbeat_resources[] = {
[0] = {
.start = PA_OUTPORT,
@@ -93,11 +111,11 @@ static struct platform_device heartbeat_device = {
#ifdef CONFIG_MFD_SM501
static struct plat_serial8250_port uart_platform_data[] = {
{
- .membase = (void __iomem *)VOYAGER_UART_BASE,
- .mapbase = VOYAGER_UART_BASE,
+ .membase = (void __iomem *)0xb3e30000,
+ .mapbase = 0xb3e30000,
.iotype = UPIO_MEM,
- .irq = IRQ_SM501_U0,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .irq = IRQ_VOYAGER,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
.regshift = 2,
.uartclk = (9600 * 16),
},
@@ -124,14 +142,67 @@ static struct resource sm501_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
- .start = IRQ_SM501_CV,
+ .start = IRQ_VOYAGER,
.flags = IORESOURCE_IRQ,
},
};
+static struct fb_videomode sm501_default_mode = {
+ .pixclock = 35714,
+ .xres = 640,
+ .yres = 480,
+ .left_margin = 105,
+ .right_margin = 50,
+ .upper_margin = 35,
+ .lower_margin = 0,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct sm501_platdata_fbsub sm501_pdata_fbsub_pnl = {
+ .def_bpp = 16,
+ .def_mode = &sm501_default_mode,
+ .flags = SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT,
+};
+
+static struct sm501_platdata_fbsub sm501_pdata_fbsub_crt = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+
+};
+
+static struct sm501_platdata_fb sm501_fb_pdata = {
+ .fb_route = SM501_FB_OWN,
+ .fb_crt = &sm501_pdata_fbsub_crt,
+ .fb_pnl = &sm501_pdata_fbsub_pnl,
+ .flags = SM501_FBPD_SWAP_FB_ENDIAN,
+};
+
+static struct sm501_initdata sm501_initdata = {
+ .gpio_high = {
+ .set = 0x00001fe0,
+ .mask = 0x0,
+ },
+ .devices = SM501_USE_USB_HOST,
+};
+
+static struct sm501_platdata sm501_platform_data = {
+ .init = &sm501_initdata,
+ .fb = &sm501_fb_pdata,
+};
+
static struct platform_device sm501_device = {
.name = "sm501",
.id = -1,
+ .dev = {
+ .platform_data = &sm501_platform_data,
+ },
.num_resources = ARRAY_SIZE(sm501_resources),
.resource = sm501_resources,
};
@@ -145,10 +216,12 @@ static struct platform_device *rts7751r2d_devices[] __initdata = {
#endif
&cf_ide_device,
&heartbeat_device,
+ &spi_sh_sci_device,
};
static int __init rts7751r2d_devices_setup(void)
{
+ spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
return platform_add_devices(rts7751r2d_devices,
ARRAY_SIZE(rts7751r2d_devices));
}
@@ -192,6 +265,7 @@ u8 rts7751r2d_readb(void __iomem *addr)
*/
static void __init rts7751r2d_setup(char **cmdline_p)
{
+ void __iomem *sm501_reg;
u16 ver = ctrl_inw(PA_VERREG);
printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
@@ -202,7 +276,30 @@ static void __init rts7751r2d_setup(char **cmdline_p)
ctrl_outw(0x0000, PA_OUTPORT);
pm_power_off = rts7751r2d_power_off;
- voyagergx_serial_init();
+ /* sm501 dram configuration:
+ * ColSizeX = 11 - External Memory Column Size: 256 words.
+ * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks.
+ * RstX = 1 - External Memory Reset: Normal.
+ * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks.
+ * BwC = 1 - Local Memory Block Write Cycle Time: 2 clocks.
+ * BwP = 1 - Local Memory Block Write to Pre-Charge Delay: 1 clock.
+ * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks.
+ * Rst = 1 - Internal Memory Reset: Normal.
+ * RA = 1 - Internal Memory Remain in Active State: Do not remain.
+ */
+
+ sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
+ writel(readl(sm501_reg) | 0x00f107c0, sm501_reg);
+
+ /*
+ * Power Mode Gate - Enable UART0
+ */
+
+ sm501_reg = (void __iomem *)0xb3e00000 + SM501_POWER_MODE_0_GATE;
+ writel(readl(sm501_reg) | (1 << SM501_GATE_UART0), sm501_reg);
+
+ sm501_reg = (void __iomem *)0xb3e00000 + SM501_POWER_MODE_1_GATE;
+ writel(readl(sm501_reg) | (1 << SM501_GATE_UART0), sm501_reg);
}
/*
@@ -215,8 +312,4 @@ static struct sh_machine_vector mv_rts7751r2d __initmv = {
.mv_irq_demux = rts7751r2d_irq_demux,
.mv_writeb = rts7751r2d_writeb,
.mv_readb = rts7751r2d_readb,
-#if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD)
- .mv_consistent_alloc = voyagergx_consistent_alloc,
- .mv_consistent_free = voyagergx_consistent_free,
-#endif
};
diff --git a/arch/sh/boards/renesas/sdk7780/Kconfig b/arch/sh/boards/renesas/sdk7780/Kconfig
new file mode 100644
index 000000000000..e4f5b6985be1
--- /dev/null
+++ b/arch/sh/boards/renesas/sdk7780/Kconfig
@@ -0,0 +1,23 @@
+if SH_SDK7780
+
+choice
+ prompt "SDK7780 options"
+ default SH_SDK7780_BASE
+
+config SH_SDK7780_STANDALONE
+ bool "SDK7780 board support"
+ depends on CPU_SUBTYPE_SH7780
+ help
+ Selecting this option will enable support for the
+ standalone version of the SDK7780. If in doubt, say Y.
+
+config SH_SDK7780_BASE
+ bool "SDK7780 with base-board support"
+ depends on CPU_SUBTYPE_SH7780
+ help
+ Selecting this option will enable support for the expansion
+ baseboard devices. If in doubt, say Y.
+
+endchoice
+
+endif
diff --git a/arch/sh/boards/renesas/sdk7780/Makefile b/arch/sh/boards/renesas/sdk7780/Makefile
new file mode 100644
index 000000000000..3d8f0befc35d
--- /dev/null
+++ b/arch/sh/boards/renesas/sdk7780/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the SDK7780 specific parts of the kernel
+#
+obj-y := setup.o irq.o
+
diff --git a/arch/sh/boards/renesas/sdk7780/irq.c b/arch/sh/boards/renesas/sdk7780/irq.c
new file mode 100644
index 000000000000..87cdc578f6ff
--- /dev/null
+++ b/arch/sh/boards/renesas/sdk7780/irq.c
@@ -0,0 +1,46 @@
+/*
+ * linux/arch/sh/boards/renesas/sdk7780/irq.c
+ *
+ * Renesas Technology Europe SDK7780 Support.
+ *
+ * Copyright (C) 2008 Nicholas Beck <nbeck@mpc-data.co.uk>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/sdk7780.h>
+
+enum {
+ UNUSED = 0,
+ /* board specific interrupt sources */
+ SMC91C111, /* Ethernet controller */
+};
+
+static struct intc_vect fpga_vectors[] __initdata = {
+ INTC_IRQ(SMC91C111, IRQ_ETHERNET),
+};
+
+static struct intc_mask_reg fpga_mask_registers[] __initdata = {
+ { 0, FPGA_IRQ0MR, 16,
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, SMC91C111, 0, 0, 0, 0 } },
+};
+
+static DECLARE_INTC_DESC(fpga_intc_desc, "sdk7780-irq", fpga_vectors,
+ NULL, fpga_mask_registers, NULL, NULL);
+
+void __init init_sdk7780_IRQ(void)
+{
+ printk(KERN_INFO "Using SDK7780 interrupt controller.\n");
+
+ ctrl_outw(0xFFFF, FPGA_IRQ0MR);
+ /* Setup IRL 0-3 */
+ ctrl_outw(0x0003, FPGA_IMSR);
+ plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+ register_intc_controller(&fpga_intc_desc);
+}
diff --git a/arch/sh/boards/renesas/sdk7780/setup.c b/arch/sh/boards/renesas/sdk7780/setup.c
new file mode 100644
index 000000000000..5df32f201870
--- /dev/null
+++ b/arch/sh/boards/renesas/sdk7780/setup.c
@@ -0,0 +1,109 @@
+/*
+ * arch/sh/boards/renesas/sdk7780/setup.c
+ *
+ * Renesas Solutions SH7780 SDK Support
+ * Copyright (C) 2008 Nicholas Beck <nbeck@mpc-data.co.uk>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pata_platform.h>
+#include <asm/machvec.h>
+#include <asm/sdk7780.h>
+#include <asm/heartbeat.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#define GPIO_PECR 0xFFEA0008
+
+//* Heartbeat */
+static struct heartbeat_data heartbeat_data = {
+ .regsize = 16,
+};
+
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = PA_LED,
+ .end = PA_LED,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = &heartbeat_data,
+ },
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+/* SMC91x */
+static struct resource smc91x_eth_resources[] = {
+ [0] = {
+ .name = "smc91x-regs" ,
+ .start = PA_LAN + 0x300,
+ .end = PA_LAN + 0x300 + 0x10 ,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_ETHERNET,
+ .end = IRQ_ETHERNET,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_eth_device = {
+ .name = "smc91x",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(smc91x_eth_resources),
+ .resource = smc91x_eth_resources,
+};
+
+static struct platform_device *sdk7780_devices[] __initdata = {
+ &heartbeat_device,
+ &smc91x_eth_device,
+};
+
+static int __init sdk7780_devices_setup(void)
+{
+ return platform_add_devices(sdk7780_devices,
+ ARRAY_SIZE(sdk7780_devices));
+}
+device_initcall(sdk7780_devices_setup);
+
+static void __init sdk7780_setup(char **cmdline_p)
+{
+ u16 ver = ctrl_inw(FPGA_FPVERR);
+ u16 dateStamp = ctrl_inw(FPGA_FPDATER);
+
+ printk(KERN_INFO "Renesas Technology Europe SDK7780 support.\n");
+ printk(KERN_INFO "Board version: %d (revision %d), "
+ "FPGA version: %d (revision %d), datestamp : %d\n",
+ (ver >> 12) & 0xf, (ver >> 8) & 0xf,
+ (ver >> 4) & 0xf, ver & 0xf,
+ dateStamp);
+
+ /* Setup pin mux'ing for PCIC */
+ ctrl_outw(0x0000, GPIO_PECR);
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_se7780 __initmv = {
+ .mv_name = "Renesas SDK7780-R3" ,
+ .mv_setup = sdk7780_setup,
+ .mv_nr_irqs = 111,
+ .mv_init_irq = init_sdk7780_IRQ,
+};
+
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index 1b0f5be01d10..59f552c13349 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -35,17 +35,28 @@ $(obj)/compressed/vmlinux: FORCE
KERNEL_LOAD := $(shell /bin/bash -c 'printf "0x%8x" \
$$[$(CONFIG_PAGE_OFFSET) + \
$(CONFIG_MEMORY_START) + \
+ $(CONFIG_ZERO_PAGE_OFFSET)]')
+
+KERNEL_ENTRY := $(shell /bin/bash -c 'printf "0x%8x" \
+ $$[$(CONFIG_PAGE_OFFSET) + \
+ $(CONFIG_MEMORY_START) + \
$(CONFIG_ZERO_PAGE_OFFSET)+0x1000]')
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
- -C none -a $(KERNEL_LOAD) -e $(KERNEL_LOAD) \
+ -C none -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
-$(obj)/uImage: $(obj)/zImage FORCE
+$(obj)/uImage: $(obj)/vmlinux.bin.gz FORCE
$(call if_changed,uimage)
@echo ' Image $@ is ready'
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
$(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
$(call if_changed,objcopy)
@@ -54,4 +65,5 @@ OBJCOPYFLAGS_uImage.srec := -I binary -O srec
$(obj)/uImage.srec: $(obj)/uImage
$(call if_changed,objcopy)
-clean-files += uImage uImage.srec vmlinux.srec
+clean-files += uImage uImage.srec vmlinux.srec \
+ vmlinux.bin vmlinux.bin.gz
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 906a13f82fe0..efb01dc3c8c3 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -1,43 +1,5 @@
-#
-# linux/arch/sh/boot/compressed/Makefile
-#
-# create a compressed vmlinux image from the original vmlinux
-#
-
-targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
-EXTRA_AFLAGS := -traditional
-
-OBJECTS = $(obj)/head.o $(obj)/misc.o
-
-ifdef CONFIG_SH_STANDARD_BIOS
-OBJECTS += $(obj)/../../kernel/sh_bios.o
+ifeq ($(CONFIG_SUPERH32),y)
+include ${srctree}/arch/sh/boot/compressed/Makefile_32
+else
+include ${srctree}/arch/sh/boot/compressed/Makefile_64
endif
-
-#
-# IMAGE_OFFSET is the load offset of the compression loader
-#
-IMAGE_OFFSET := $(shell /bin/bash -c 'printf "0x%08x" \
- $$[$(CONFIG_PAGE_OFFSET) + \
- $(CONFIG_MEMORY_START) + \
- $(CONFIG_BOOT_LINK_OFFSET)]')
-
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
-
-
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
- $(call if_changed,ld)
- @:
-
-$(obj)/vmlinux.bin: vmlinux FORCE
- $(call if_changed,objcopy)
-
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
-
-LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh-linux -T
-OBJCOPYFLAGS += -R .empty_zero_page
-
-$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
- $(call if_changed,ld)
diff --git a/arch/sh/boot/compressed/Makefile_32 b/arch/sh/boot/compressed/Makefile_32
new file mode 100644
index 000000000000..6ac8d4a4ed1d
--- /dev/null
+++ b/arch/sh/boot/compressed/Makefile_32
@@ -0,0 +1,43 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets := vmlinux vmlinux.bin vmlinux.bin.gz \
+ head_32.o misc_32.o piggy.o
+EXTRA_AFLAGS := -traditional
+
+OBJECTS = $(obj)/head_32.o $(obj)/misc_32.o
+
+ifdef CONFIG_SH_STANDARD_BIOS
+OBJECTS += $(obj)/../../kernel/sh_bios.o
+endif
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+#
+IMAGE_OFFSET := $(shell /bin/bash -c 'printf "0x%08x" \
+ $$[$(CONFIG_PAGE_OFFSET) + \
+ $(CONFIG_MEMORY_START) + \
+ $(CONFIG_BOOT_LINK_OFFSET)]')
+
+LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+ $(call if_changed,ld)
+ @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh-linux -T
+OBJCOPYFLAGS += -R .empty_zero_page
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+ $(call if_changed,ld)
diff --git a/arch/sh/boot/compressed/Makefile_64 b/arch/sh/boot/compressed/Makefile_64
new file mode 100644
index 000000000000..4334f2b86d8f
--- /dev/null
+++ b/arch/sh/boot/compressed/Makefile_64
@@ -0,0 +1,45 @@
+#
+# arch/sh/boot/compressed/Makefile_64
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+# Copyright (C) 2002 Stuart Menefy
+# Copyright (C) 2004 Paul Mundt
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+targets := vmlinux vmlinux.bin vmlinux.bin.gz \
+ head_64.o misc_64.o cache.o piggy.o
+EXTRA_AFLAGS := -traditional
+
+OBJECTS := $(obj)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o \
+ $(obj)/cache.o
+
+#
+# ZIMAGE_OFFSET is the load offset of the compression loader
+# (4M for the kernel plus 64K for this loader)
+#
+ZIMAGE_OFFSET := $(shell /bin/bash -c 'printf "0x%08x" \
+ $$[$(CONFIG_PAGE_OFFSET)+0x400000+0x10000]')
+
+LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \
+ -T $(obj)/../../kernel/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+ $(call if_changed,ld)
+ @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T
+OBJCOPYFLAGS += -R .empty_zero_page
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+ $(call if_changed,ld)
diff --git a/arch/sh/boot/compressed/cache.c b/arch/sh/boot/compressed/cache.c
new file mode 100644
index 000000000000..e27fc74f228c
--- /dev/null
+++ b/arch/sh/boot/compressed/cache.c
@@ -0,0 +1,12 @@
+int cache_control(unsigned int command)
+{
+ volatile unsigned int *p = (volatile unsigned int *) 0x80000000;
+ int i;
+
+ for (i = 0; i < (32 * 1024); i += 32) {
+ (void)*p;
+ p += (32 / sizeof (int));
+ }
+
+ return 0;
+}
diff --git a/arch/sh/boot/compressed/head.S b/arch/sh/boot/compressed/head_32.S
index a8399b013729..a8399b013729 100644
--- a/arch/sh/boot/compressed/head.S
+++ b/arch/sh/boot/compressed/head_32.S
diff --git a/arch/sh/boot/compressed/head_64.S b/arch/sh/boot/compressed/head_64.S
new file mode 100644
index 000000000000..1d4ecbfc767c
--- /dev/null
+++ b/arch/sh/boot/compressed/head_64.S
@@ -0,0 +1,163 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * arch/shmedia/boot/compressed/head.S
+ *
+ * Copied from
+ * arch/shmedia/kernel/head.S
+ * which carried the copyright:
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * Modification for compressed loader:
+ * Copyright (C) 2002 Stuart Menefy (stuart.menefy@st.com)
+ */
+#include <linux/linkage.h>
+#include <asm/cache.h>
+#include <asm/cpu/mmu_context.h>
+#include <asm/cpu/registers.h>
+
+/*
+ * Fixed TLB entries to identity map the beginning of RAM
+ */
+#define MMUIR_TEXT_H 0x0000000000000003 | CONFIG_MEMORY_START
+ /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+#define MMUIR_TEXT_L 0x000000000000009a | CONFIG_MEMORY_START
+ /* 512 Mb, Cacheable (Write-back), execute, Not User, Ph. Add. */
+
+#define MMUDR_CACHED_H 0x0000000000000003 | CONFIG_MEMORY_START
+ /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+#define MMUDR_CACHED_L 0x000000000000015a | CONFIG_MEMORY_START
+ /* 512 Mb, Cacheable (Write-back), read/write, Not User, Ph. Add. */
+
+#define ICCR0_INIT_VAL ICCR0_ON | ICCR0_ICI /* ICE + ICI */
+#define ICCR1_INIT_VAL ICCR1_NOLOCK /* No locking */
+
+#if 1
+#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WB /* OCE + OCI + WB */
+#else
+#define OCCR0_INIT_VAL OCCR0_OFF
+#endif
+#define OCCR1_INIT_VAL OCCR1_NOLOCK /* No locking */
+
+ .text
+
+ .global startup
+startup:
+ /*
+ * Prevent speculative fetch on device memory due to
+ * uninitialized target registers.
+ * This must be executed before the first branch.
+ */
+ ptabs/u r63, tr0
+ ptabs/u r63, tr1
+ ptabs/u r63, tr2
+ ptabs/u r63, tr3
+ ptabs/u r63, tr4
+ ptabs/u r63, tr5
+ ptabs/u r63, tr6
+ ptabs/u r63, tr7
+ synci
+
+ /*
+ * Set initial TLB entries for cached and uncached regions.
+ * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
+ */
+ /* Clear ITLBs */
+ pta 1f, tr1
+ movi ITLB_FIXED, r21
+ movi ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
+1: putcfg r21, 0, r63 /* Clear MMUIR[n].PTEH.V */
+ addi r21, TLB_STEP, r21
+ bne r21, r22, tr1
+
+ /* Clear DTLBs */
+ pta 1f, tr1
+ movi DTLB_FIXED, r21
+ movi DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
+1: putcfg r21, 0, r63 /* Clear MMUDR[n].PTEH.V */
+ addi r21, TLB_STEP, r21
+ bne r21, r22, tr1
+
+ /* Map one big (512Mb) page for ITLB */
+ movi ITLB_FIXED, r21
+ movi MMUIR_TEXT_L, r22 /* PTEL first */
+ putcfg r21, 1, r22 /* Set MMUIR[0].PTEL */
+ movi MMUIR_TEXT_H, r22 /* PTEH last */
+ putcfg r21, 0, r22 /* Set MMUIR[0].PTEH */
+
+ /* Map one big CACHED (512Mb) page for DTLB */
+ movi DTLB_FIXED, r21
+ movi MMUDR_CACHED_L, r22 /* PTEL first */
+ putcfg r21, 1, r22 /* Set MMUDR[0].PTEL */
+ movi MMUDR_CACHED_H, r22 /* PTEH last */
+ putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */
+
+ /* ICache */
+ movi ICCR_BASE, r21
+ movi ICCR0_INIT_VAL, r22
+ movi ICCR1_INIT_VAL, r23
+ putcfg r21, ICCR_REG0, r22
+ putcfg r21, ICCR_REG1, r23
+ synci
+
+ /* OCache */
+ movi OCCR_BASE, r21
+ movi OCCR0_INIT_VAL, r22
+ movi OCCR1_INIT_VAL, r23
+ putcfg r21, OCCR_REG0, r22
+ putcfg r21, OCCR_REG1, r23
+ synco
+
+ /*
+ * Enable the MMU.
+ * From here-on code can be non-PIC.
+ */
+ movi SR_HARMLESS | SR_ENABLE_MMU, r22
+ putcon r22, SSR
+ movi 1f, r22
+ putcon r22, SPC
+ synco
+ rte /* And now go into the hyperspace ... */
+1: /* ... that's the next instruction ! */
+
+ /* Set initial stack pointer */
+ movi datalabel stack_start, r0
+ ld.l r0, 0, r15
+
+ /*
+ * Clear bss
+ */
+ pt 1f, tr1
+ movi datalabel __bss_start, r22
+ movi datalabel _end, r23
+1: st.l r22, 0, r63
+ addi r22, 4, r22
+ bne r22, r23, tr1
+
+ /*
+ * Decompress the kernel.
+ */
+ pt decompress_kernel, tr0
+ blink tr0, r18
+
+ /*
+ * Disable the MMU.
+ */
+ movi SR_HARMLESS, r22
+ putcon r22, SSR
+ movi 1f, r22
+ putcon r22, SPC
+ synco
+ rte /* And now go into the hyperspace ... */
+1: /* ... that's the next instruction ! */
+
+ /* Jump into the decompressed kernel */
+ movi datalabel (CONFIG_MEMORY_START + 0x2000)+1, r19
+ ptabs r19, tr0
+ blink tr0, r18
+
+ /* Shouldn't return here, but just in case, loop forever */
+ pt 1f, tr0
+1: blink tr0, r63
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc_32.c
index df65e305acf7..adcea31e663e 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc_32.c
@@ -230,7 +230,10 @@ long* stack_start = &user_stack[STACK_SIZE];
void decompress_kernel(void)
{
output_data = 0;
- output_ptr = P2SEGADDR((unsigned long)&_text+PAGE_SIZE);
+ output_ptr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+#ifdef CONFIG_29BIT
+ output_ptr |= P2SEG;
+#endif
free_mem_ptr = (unsigned long)&_end;
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
diff --git a/arch/sh/boot/compressed/misc_64.c b/arch/sh/boot/compressed/misc_64.c
new file mode 100644
index 000000000000..a006ef89b9dd
--- /dev/null
+++ b/arch/sh/boot/compressed/misc_64.c
@@ -0,0 +1,250 @@
+/*
+ * arch/sh/boot/compressed/misc_64.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SHmedia from sh by Stuart Menefy, May 2002
+ */
+
+#include <asm/uaccess.h>
+
+/* cache.c */
+#define CACHE_ENABLE 0
+#define CACHE_DISABLE 1
+int cache_control(unsigned int command);
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static void puts(const char *);
+
+extern int _text; /* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE 0x10000
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+ void *p;
+
+ if (size < 0)
+ error("Malloc error\n");
+ if (free_mem_ptr == 0)
+ error("Memory error\n");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *) free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("\nOut of memory\n");
+
+ return p;
+}
+
+static void free(void *where)
+{ /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
+void puts(const char *s)
+{
+}
+
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = (char *) s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+ return s;
+}
+
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+ int i;
+ char *d = (char *) __dest, *s = (char *) __src;
+
+ for (i = 0; i < __n; i++)
+ d[i] = s[i];
+ return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+ if (insize != 0) {
+ error("ran out of input data\n");
+ }
+
+ inbuf = input_data;
+ insize = input_len;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg) outcnt;
+ output_ptr += (ulg) outcnt;
+ outcnt = 0;
+ puts(".");
+}
+
+static void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while (1) ; /* Halt */
+}
+
+#define STACK_SIZE (4096)
+long __attribute__ ((aligned(8))) user_stack[STACK_SIZE];
+long *stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+ output_data = (uch *) (CONFIG_MEMORY_START + 0x2000);
+ free_mem_ptr = (unsigned long) &_end;
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+ makecrc();
+ puts("Uncompressing Linux... ");
+ cache_control(CACHE_ENABLE);
+ gunzip();
+ puts("\n");
+
+#if 0
+ /* When booting from ROM may want to do something like this if the
+ * boot loader doesn't.
+ */
+
+ /* Set up the parameters and command line */
+ {
+ volatile unsigned int *parambase =
+ (int *) (CONFIG_MEMORY_START + 0x1000);
+
+ parambase[0] = 0x1; /* MOUNT_ROOT_RDONLY */
+ parambase[1] = 0x0; /* RAMDISK_FLAGS */
+ parambase[2] = 0x0200; /* ORIG_ROOT_DEV */
+ parambase[3] = 0x0; /* LOADER_TYPE */
+ parambase[4] = 0x0; /* INITRD_START */
+ parambase[5] = 0x0; /* INITRD_SIZE */
+ parambase[6] = 0;
+
+ strcpy((char *) ((int) parambase + 0x100),
+ "console=ttySC0,38400");
+ }
+#endif
+
+ puts("Ok, booting the kernel.\n");
+
+ cache_control(CACHE_DISABLE);
+}
diff --git a/arch/sh/boot/compressed/vmlinux_64.lds b/arch/sh/boot/compressed/vmlinux_64.lds
new file mode 100644
index 000000000000..59c2ef4aeda5
--- /dev/null
+++ b/arch/sh/boot/compressed/vmlinux_64.lds
@@ -0,0 +1,64 @@
+/*
+ * ld script to make compressed SuperH/shmedia Linux kernel+decompression
+ * bootstrap
+ * Modified by Stuart Menefy from arch/sh/vmlinux.lds.S written by Niibe Yutaka
+ */
+
+
+#ifdef CONFIG_LITTLE_ENDIAN
+/* OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") */
+#define NOP 0x6ff0fff0
+#else
+/* OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") */
+#define NOP 0xf0fff06f
+#endif
+
+OUTPUT_FORMAT("elf32-sh64-linux")
+OUTPUT_ARCH(sh)
+ENTRY(_start)
+
+#define ALIGNED_GAP(section, align) (((ADDR(section)+SIZEOF(section)+(align)-1) & ~((align)-1))-ADDR(section))
+#define FOLLOWING(section, align) AT (LOADADDR(section) + ALIGNED_GAP(section,align))
+
+SECTIONS
+{
+ _text = .; /* Text and read-only data */
+
+ .text : {
+ *(.text)
+ *(.text64)
+ *(.text..SHmedia32)
+ *(.fixup)
+ *(.gnu.warning)
+ } = NOP
+ . = ALIGN(4);
+ .rodata : { *(.rodata) }
+
+ /* There is no 'real' reason for eight byte alignment, four would work
+ * as well, but gdb downloads much (*4) faster with this.
+ */
+ . = ALIGN(8);
+ .image : { *(.image) }
+ . = ALIGN(4);
+ _etext = .; /* End of text section */
+
+ .data : /* Data */
+ FOLLOWING(.image, 4)
+ {
+ _data = .;
+ *(.data)
+ }
+ _data_image = LOADADDR(.data);/* Address of data section in ROM */
+
+ _edata = .; /* End of data section */
+
+ .stack : { stack = .; _stack = .; }
+
+ . = ALIGN(4);
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ . = ALIGN(4);
+ _end = . ;
+}
diff --git a/arch/sh/cchips/voyagergx/Makefile b/arch/sh/cchips/voyagergx/Makefile
deleted file mode 100644
index f73963cb3744..000000000000
--- a/arch/sh/cchips/voyagergx/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for VoyagerGX
-#
-
-obj-y := irq.o setup.o
-
-obj-$(CONFIG_USB_OHCI_HCD) += consistent.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c
deleted file mode 100644
index 07e8b9c5a531..000000000000
--- a/arch/sh/cchips/voyagergx/consistent.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/sh/cchips/voyagergx/consistent.c
- *
- * Copyright (C) 2004 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <asm/io.h>
-
-
-struct voya_alloc_entry {
- struct list_head list;
- unsigned long ofs;
- unsigned long len;
-};
-
-static DEFINE_SPINLOCK(voya_list_lock);
-static LIST_HEAD(voya_alloc_list);
-
-#define OHCI_SRAM_START 0xb0000000
-#define OHCI_HCCA_SIZE 0x100
-#define OHCI_SRAM_SIZE 0x10000
-
-#define VOYAGER_OHCI_NAME "voyager-ohci"
-
-void *voyagergx_consistent_alloc(struct device *dev, size_t size,
- dma_addr_t *handle, gfp_t flag)
-{
- struct list_head *list = &voya_alloc_list;
- struct voya_alloc_entry *entry;
- unsigned long start, end;
- unsigned long flags;
-
- /*
- * The SM501 contains an integrated 8051 with its own SRAM.
- * Devices within the cchip can all hook into the 8051 SRAM.
- * We presently use this for the OHCI.
- *
- * Everything else goes through consistent_alloc().
- */
- if (!dev || strcmp(dev->driver->name, VOYAGER_OHCI_NAME))
- return NULL;
-
- start = OHCI_SRAM_START + OHCI_HCCA_SIZE;
-
- entry = kmalloc(sizeof(struct voya_alloc_entry), GFP_ATOMIC);
- if (!entry)
- return ERR_PTR(-ENOMEM);
-
- entry->len = (size + 15) & ~15;
-
- /*
- * The basis for this allocator is dwmw2's malloc.. the
- * Matrox allocator :-)
- */
- spin_lock_irqsave(&voya_list_lock, flags);
- list_for_each(list, &voya_alloc_list) {
- struct voya_alloc_entry *p;
-
- p = list_entry(list, struct voya_alloc_entry, list);
-
- if (p->ofs - start >= size)
- goto out;
-
- start = p->ofs + p->len;
- }
-
- end = start + (OHCI_SRAM_SIZE - OHCI_HCCA_SIZE);
- list = &voya_alloc_list;
-
- if (end - start >= size) {
-out:
- entry->ofs = start;
- list_add_tail(&entry->list, list);
- spin_unlock_irqrestore(&voya_list_lock, flags);
-
- *handle = start;
- return (void *)start;
- }
-
- kfree(entry);
- spin_unlock_irqrestore(&voya_list_lock, flags);
-
- return ERR_PTR(-EINVAL);
-}
-
-int voyagergx_consistent_free(struct device *dev, size_t size,
- void *vaddr, dma_addr_t handle)
-{
- struct voya_alloc_entry *entry;
- unsigned long flags;
-
- if (!dev || strcmp(dev->driver->name, VOYAGER_OHCI_NAME))
- return -EINVAL;
-
- spin_lock_irqsave(&voya_list_lock, flags);
- list_for_each_entry(entry, &voya_alloc_list, list) {
- if (entry->ofs != handle)
- continue;
-
- list_del(&entry->list);
- kfree(entry);
-
- break;
- }
- spin_unlock_irqrestore(&voya_list_lock, flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(voyagergx_consistent_alloc);
-EXPORT_SYMBOL(voyagergx_consistent_free);
diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c
deleted file mode 100644
index ade303876841..000000000000
--- a/arch/sh/cchips/voyagergx/irq.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -------------------------------------------------------------------- */
-/* setup_voyagergx.c: */
-/* -------------------------------------------------------------------- */
-/* This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Copyright 2003 (c) Lineo uSolutions,Inc.
-*/
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/voyagergx.h>
-#include <asm/rts7751r2d.h>
-
-enum {
- UNUSED = 0,
-
- /* voyager specific interrupt sources */
- UP, G54, G53, G52, G51, G50, G49, G48,
- I2C, PW, DMA, PCI, I2S, AC, US,
- U1, U0, CV, MC, S1, S0,
- UH, TWOD, ZD, PV, CI,
-};
-
-static struct intc_vect vectors[] __initdata = {
- INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54),
- INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52),
- INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50),
- INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48),
- INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW),
- INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI),
- INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC),
- INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1),
- INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV),
- INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1),
- INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH),
- INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD),
- INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI),
-};
-
-static struct intc_mask_reg mask_registers[] __initdata = {
- { VOYAGER_INT_MASK, 0, 32, /* "Interrupt Mask", MMIO_base + 0x30 */
- { UP, G54, G53, G52, G51, G50, G49, G48,
- I2C, PW, 0, DMA, PCI, I2S, AC, US,
- 0, 0, U1, U0, CV, MC, S1, S0,
- 0, UH, 0, 0, TWOD, ZD, PV, CI } },
-};
-
-static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors,
- NULL, NULL, mask_registers, NULL, NULL);
-
-static unsigned int voyagergx_stat2irq[32] = {
- IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D,
- 0, 0, IRQ_SM501_UH, 0,
- IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV,
- IRQ_SM501_U0, IRQ_SM501_U1, 0, 0,
- IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI,
- IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C,
- IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51,
- IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP
-};
-
-static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
-{
- unsigned long intv = ctrl_inl(INT_STATUS);
- struct irq_desc *ext_desc;
- unsigned int ext_irq;
- unsigned int k = 0;
-
- while (intv) {
- ext_irq = voyagergx_stat2irq[k];
- if (ext_irq && (intv & 1)) {
- ext_desc = irq_desc + ext_irq;
- handle_level_irq(ext_irq, ext_desc);
- }
- intv >>= 1;
- k++;
- }
-}
-
-void __init setup_voyagergx_irq(void)
-{
- printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
- IRQ_VOYAGER,
- VOYAGER_IRQ_BASE,
- VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
-
- register_intc_controller(&intc_desc);
- set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
-}
diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c
deleted file mode 100644
index 33f03027c193..000000000000
--- a/arch/sh/cchips/voyagergx/setup.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * arch/sh/cchips/voyagergx/setup.c
- *
- * Setup routines for VoyagerGX cchip.
- *
- * Copyright (C) 2003 Lineo uSolutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#include <asm/voyagergx.h>
-
-static int __init setup_voyagergx(void)
-{
- unsigned long val;
-
- val = readl((void __iomem *)DRAM_CTRL);
- val |= (DRAM_CTRL_CPU_COLUMN_SIZE_256 |
- DRAM_CTRL_CPU_ACTIVE_PRECHARGE |
- DRAM_CTRL_CPU_RESET |
- DRAM_CTRL_REFRESH_COMMAND |
- DRAM_CTRL_BLOCK_WRITE_TIME |
- DRAM_CTRL_BLOCK_WRITE_PRECHARGE |
- DRAM_CTRL_ACTIVE_PRECHARGE |
- DRAM_CTRL_RESET |
- DRAM_CTRL_REMAIN_ACTIVE);
- writel(val, (void __iomem *)DRAM_CTRL);
-
- return 0;
-}
-
-module_init(setup_voyagergx);
diff --git a/arch/sh/configs/cayman_defconfig b/arch/sh/configs/cayman_defconfig
new file mode 100644
index 000000000000..a05b278d72f5
--- /dev/null
+++ b/arch/sh/configs/cayman_defconfig
@@ -0,0 +1,1166 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc3
+# Fri Nov 23 14:15:55 2007
+#
+CONFIG_SUPERH=y
+# CONFIG_SUPERH32 is not set
+CONFIG_SUPERH64=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System type
+#
+CONFIG_CPU_SH5=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE=0x00400000
+CONFIG_32BIT=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_CACHE_WRITEBACK is not set
+# CONFIG_CACHE_WRITETHROUGH is not set
+CONFIG_CACHE_OFF=y
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+CONFIG_SH64_ID2815_WORKAROUND=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+CONFIG_SH_CAYMAN=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=50000000
+# CONFIG_TICK_ONESHOT is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_AX88796 is not set
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMC911X is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_CX23885 is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_DVB_CORE=y
+# CONFIG_DVB_CORE_ATTACH is not set
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+# CONFIG_DVB_STV0299 is not set
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+# CONFIG_DVB_TDA8083 is not set
+# CONFIG_DVB_MT312 is not set
+# CONFIG_DVB_VES1X93 is not set
+# CONFIG_DVB_S5H1420 is not set
+# CONFIG_DVB_TDA10086 is not set
+
+#
+# DVB-T (terrestrial) frontends
+#
+# CONFIG_DVB_SP8870 is not set
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_CX22700 is not set
+# CONFIG_DVB_CX22702 is not set
+# CONFIG_DVB_L64781 is not set
+# CONFIG_DVB_TDA1004X is not set
+# CONFIG_DVB_NXT6000 is not set
+# CONFIG_DVB_MT352 is not set
+# CONFIG_DVB_ZL10353 is not set
+# CONFIG_DVB_DIB3000MB is not set
+# CONFIG_DVB_DIB3000MC is not set
+# CONFIG_DVB_DIB7000M is not set
+# CONFIG_DVB_DIB7000P is not set
+
+#
+# DVB-C (cable) frontends
+#
+# CONFIG_DVB_VES1820 is not set
+# CONFIG_DVB_TDA10021 is not set
+# CONFIG_DVB_TDA10023 is not set
+# CONFIG_DVB_STV0297 is not set
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+# CONFIG_DVB_NXT200X is not set
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+# CONFIG_DVB_BCM3510 is not set
+# CONFIG_DVB_LGDT330X is not set
+# CONFIG_DVB_S5H1409 is not set
+
+#
+# Tuners/PLL support
+#
+# CONFIG_DVB_PLL is not set
+# CONFIG_DVB_TDA826X is not set
+# CONFIG_DVB_TDA827X is not set
+# CONFIG_DVB_TUNER_QT1010 is not set
+# CONFIG_DVB_TUNER_MT2060 is not set
+# CONFIG_DVB_TUNER_MT2266 is not set
+# CONFIG_DVB_TUNER_MT2131 is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+
+#
+# Miscellaneous devices
+#
+# CONFIG_DVB_LNBP21 is not set
+# CONFIG_DVB_ISL6421 is not set
+# CONFIG_DVB_TUA6100 is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_DEBUG_BOOTMEM is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+CONFIG_SH64_PROC_ASIDS=y
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_POOR_MANS_STRACE is not set
+# CONFIG_SH_ALPHANUMERIC is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/hs7751rvoip_defconfig b/arch/sh/configs/hs7751rvoip_defconfig
deleted file mode 100644
index 5d9da5a02759..000000000000
--- a/arch/sh/configs/hs7751rvoip_defconfig
+++ /dev/null
@@ -1,908 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct 3 13:04:52 2006
-#
-CONFIG_SUPERH=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-CONFIG_UID16=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_KALLSYMS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# Block layer
-#
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-CONFIG_SH_HS7751RVOIP=y
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
-CONFIG_CPU_SH4=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7705 is not set
-# CONFIG_CPU_SUBTYPE_SH7706 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7091 is not set
-# CONFIG_CPU_SUBTYPE_SH7750R is not set
-# CONFIG_CPU_SUBTYPE_SH7750S is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7770 is not set
-# CONFIG_CPU_SUBTYPE_SH7780 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
-# CONFIG_CPU_SUBTYPE_SH7343 is not set
-
-#
-# Memory management options
-#
-CONFIG_MMU=y
-CONFIG_PAGE_OFFSET=0x80000000
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_VSYSCALL=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-
-#
-# Cache configuration
-#
-# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-
-#
-# Processor features
-#
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
-# CONFIG_SH_STORE_QUEUES is not set
-CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_SR_RB=y
-
-#
-# Timer support
-#
-CONFIG_SH_TMU=y
-
-#
-# HS7751RVoIP options
-#
-CONFIG_HS7751RVOIP_CODEC=y
-CONFIG_SH_PCLK_FREQ=60000000
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# DMA support
-#
-# CONFIG_SH_DMA is not set
-
-#
-# Companion Chips
-#
-# CONFIG_HD6446X_SERIES is not set
-
-#
-# Kernel features
-#
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-# CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT_NONE is not set
-# CONFIG_PREEMPT_VOLUNTARY is not set
-CONFIG_PREEMPT=y
-CONFIG_PREEMPT_BKL=y
-
-#
-# Boot options
-#
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="mem=64M console=ttySC1,115200 root=/dev/hda1"
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_ASK_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_MULTIPLE_TABLES is not set
-# CONFIG_IP_ROUTE_MULTIPATH is not set
-# CONFIG_IP_ROUTE_VERBOSE is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
-# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=1
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# PHY device support
-#
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_STNIC is not set
-# CONFIG_SMC91X is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-
-#
-# Hardware Monitoring support
-#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_EARLY_SCIF_CONSOLE is not set
-# CONFIG_KGDB is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_MANAGER=m
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
index 2e43a2a971a9..0dc1ce7b9349 100644
--- a/arch/sh/configs/r7785rp_defconfig
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -1,9 +1,10 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24-rc2
-# Tue Nov 13 20:34:57 2007
+# Linux kernel version: 2.6.24-rc3
+# Fri Nov 23 14:03:57 2007
#
CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -39,6 +40,7 @@ CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
# CONFIG_TASKSTATS is not set
# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -130,6 +132,8 @@ CONFIG_CPU_SUBTYPE_SH7785=y
# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
#
# Memory management options
@@ -139,7 +143,8 @@ CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x08000000
CONFIG_MEMORY_SIZE=0x08000000
-# CONFIG_32BIT is not set
+CONFIG_29BIT=y
+# CONFIG_PMB is not set
# CONFIG_X2TLB is not set
CONFIG_VSYSCALL=y
# CONFIG_NUMA is not set
@@ -158,6 +163,7 @@ CONFIG_PAGE_SIZE_4KB=y
CONFIG_HUGETLB_PAGE_SIZE_1MB=y
# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -701,6 +707,7 @@ CONFIG_DEVPORT=y
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_I5K_AMB is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_F71882FG is not set
# CONFIG_SENSORS_IT87 is not set
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/sdk7780_defconfig
index 12cc01910cf8..bb9bcd6591ab 100644
--- a/arch/sh/configs/r7780rp_defconfig
+++ b/arch/sh/configs/sdk7780_defconfig
@@ -1,9 +1,10 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc7
-# Tue May 1 12:28:39 2007
+# Linux kernel version: 2.6.24-rc7
+# Tue Jan 22 11:34:03 2008
#
CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -11,149 +12,107 @@ CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION="_SDK7780"
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-# CONFIG_SYSFS_DEPRECATED is not set
-# CONFIG_RELAY is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
CONFIG_UID16=y
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7722_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7780_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-CONFIG_SH_HIGHLANDER=y
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_LBOX_RE2 is not set
-# CONFIG_SH_UNKNOWN is not set
-CONFIG_SH_R7780RP=y
-# CONFIG_SH_R7780MP is not set
-# CONFIG_SH_R7785RP is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH4=y
CONFIG_CPU_SH4A=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
# CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
@@ -161,10 +120,8 @@ CONFIG_CPU_SH4A=y
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
# CONFIG_CPU_SUBTYPE_SH7712 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -173,38 +130,33 @@ CONFIG_CPU_SH4A=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
# CONFIG_CPU_SUBTYPE_SH7770 is not set
CONFIG_CPU_SUBTYPE_SH7780=y
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x08000000
CONFIG_MEMORY_SIZE=0x08000000
-# CONFIG_32BIT is not set
+CONFIG_29BIT=y
+# CONFIG_PMB is not set
CONFIG_VSYSCALL=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -213,23 +165,27 @@ CONFIG_HUGETLB_PAGE_SIZE_64K=y
# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
+CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
#
# Processor features
@@ -237,20 +193,31 @@ CONFIG_ZONE_DMA_FLAG=0
CONFIG_CPU_LITTLE_ENDIAN=y
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_SH_FPU=y
-# CONFIG_SH_DSP is not set
CONFIG_SH_STORE_QUEUES=y
-CONFIG_SPECULATIVE_EXECUTION=y
+# CONFIG_SPECULATIVE_EXECUTION is not set
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+# CONFIG_SH_7780_SOLUTION_ENGINE is not set
+CONFIG_SH_SDK7780=y
+# CONFIG_SH_HIGHLANDER is not set
+# CONFIG_SH_SDK7780_STANDALONE is not set
+CONFIG_SH_SDK7780_BASE=y
#
# Timer and clock configuration
#
CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=28
-CONFIG_NO_IDLE_HZ=y
-CONFIG_SH_PCLK_FREQ=32000000
+CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
#
# CPU Frequency scaling
@@ -260,18 +227,20 @@ CONFIG_SH_PCLK_FREQ=32000000
#
# DMA support
#
-# CONFIG_SH_DMA is not set
+CONFIG_SH_DMA_API=y
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=12
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
#
# Additional SuperH Device Drivers
#
-# CONFIG_HEARTBEAT is not set
-CONFIG_PUSH_SWITCH=y
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
#
# Kernel features
@@ -281,22 +250,21 @@ CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
-CONFIG_KEXEC=y
+# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
-# CONFIG_SMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_PREEMPT_BKL=y
+CONFIG_GUSA=y
#
# Boot options
#
CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_BOOT_LINK_OFFSET=0x01800000
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="mem=128M console=ttySC0,115200 root=/dev/sda1"
+CONFIG_CMDLINE="mem=128M console=tty0 console=ttySC0,115200 ip=bootp root=/dev/nfs nfsroot=192.168.0.1:/home/rootfs"
#
# Bus options
@@ -305,31 +273,40 @@ CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-# CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_LEGACY is not set
+CONFIG_PCI_DEBUG=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=y
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -337,7 +314,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -347,7 +323,7 @@ CONFIG_XFRM=y
# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_ASK_IP_FIB_HASH=y
# CONFIG_IP_FIB_TRIE is not set
@@ -356,52 +332,55 @@ CONFIG_IP_FIB_HASH=y
# CONFIG_IP_ROUTE_MULTIPATH is not set
# CONFIG_IP_ROUTE_VERBOSE is not set
CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
-CONFIG_BRIDGE=m
+# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
-CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
@@ -409,11 +388,39 @@ CONFIG_LLC=m
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RR is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_INGRESS is not set
#
-# QoS and/or fair queueing
+# Classification
#
-# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_POLICE is not set
+CONFIG_NET_SCH_FIFO=y
#
# Network testing
@@ -422,8 +429,17 @@ CONFIG_LLC=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -432,69 +448,108 @@ CONFIG_WIRELESS_EXT=y
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_1284 is not set
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_PLATFORM=y
+
+#
+# PCI IDE chipsets support
+#
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDE_ARCH_OBSOLETE_INIT is not set
+# CONFIG_BLK_DEV_HD is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -503,8 +558,9 @@ CONFIG_SCSI_PROC_FS=y
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=m
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
#
@@ -514,19 +570,17 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
@@ -536,7 +590,6 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
@@ -559,10 +612,7 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_AHCI is not set
@@ -574,7 +624,7 @@ CONFIG_ATA=y
# CONFIG_SATA_QSTOR is not set
# CONFIG_SATA_PROMISE is not set
# CONFIG_SATA_SX4 is not set
-CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL is not set
# CONFIG_SATA_SIL24 is not set
# CONFIG_SATA_SIS is not set
# CONFIG_SATA_ULI is not set
@@ -585,6 +635,7 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -604,8 +655,10 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_NETCELL is not set
# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RZ1000 is not set
@@ -616,185 +669,87 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
-CONFIG_PATA_PLATFORM=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
+# CONFIG_PATA_PLATFORM is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
# CONFIG_FUSION is not set
-# CONFIG_FUSION_SPI is not set
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+# CONFIG_AX88796 is not set
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
+CONFIG_SMC91X=y
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=m
-# CONFIG_PCNET32_NAPI is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=m
-CONFIG_8139TOO=m
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-CONFIG_8139TOO_8129=y
-# CONFIG_8139_OLD_RX_RESET is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-CONFIG_VIA_RHINE=m
-CONFIG_VIA_RHINE_MMIO=y
-# CONFIG_VIA_RHINE_NAPI is not set
-# CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=m
-# CONFIG_E1000_NAPI is not set
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_NET_POCKET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_NET_WIRELESS_RTNETLINK is not set
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2200 is not set
-CONFIG_HERMES=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+# Wireless LAN
#
-CONFIG_PRISM54=m
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
-# Wan interfaces
+# USB Network Adapters
#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_NET_PCMCIA is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -802,17 +757,17 @@ CONFIG_NET_WIRELESS=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
@@ -825,8 +780,19 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -836,6 +802,7 @@ CONFIG_KEYBOARD_ATKBD=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PARKBD is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
@@ -844,7 +811,10 @@ CONFIG_SERIO_LIBPS2=y
#
# Character devices
#
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -864,32 +834,22 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
#
-# TPM devices
+# PCMCIA character devices
#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -897,22 +857,27 @@ CONFIG_HW_RANDOM=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
#
-# Hardware Monitoring support
+# Sonics Silicon Backplane
#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_PCMCIAHOST_POSSIBLE=y
+# CONFIG_SSB_PCMCIAHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_DRIVER_PCICORE=y
#
# Multifunction device drivers
@@ -923,22 +888,93 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Digital Video Broadcasting Devices
+# Display device support
#
-# CONFIG_DVB is not set
+CONFIG_DISPLAY_SUPPORT=y
#
-# Graphics support
+# Display hardware drivers
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_SUPERH_MONO=y
+CONFIG_LOGO_SUPERH_VGA16=y
+CONFIG_LOGO_SUPERH_CLUT224=y
#
# Sound
#
-CONFIG_SOUND=m
+CONFIG_SOUND=y
#
# Advanced Linux Sound Architecture
@@ -948,126 +984,162 @@ CONFIG_SOUND=m
#
# Open Sound System
#
-CONFIG_SOUND_PRIME=m
-# CONFIG_OBSOLETE_OSS is not set
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_ICH is not set
+CONFIG_SOUND_PRIME=y
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
#
-# USB support
+# USB Input Devices
#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# Miscellaneous USB options
#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# LED devices
+# USB Host Controller Drivers
#
-# CONFIG_NEW_LEDS is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
-# LED drivers
+# USB Device Class drivers
#
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=y
#
-# LED Triggers
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
-# InfiniBand support
+# may also be needed; see USB_STORAGE Help for more information
#
-# CONFIG_INFINIBAND is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# USB Imaging devices
#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
#
-# Real Time Clock
+# USB port drivers
#
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
+# CONFIG_USB_USS720 is not set
#
-# RTC interfaces
+# USB Serial Converter support
#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_USB_SERIAL is not set
#
-# RTC drivers
+# USB Miscellaneous drivers
#
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_SH=y
-# CONFIG_RTC_DRV_TEST is not set
-# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
#
-# DMA Engine support
+# USB DSL modem support
#
-# CONFIG_DMA_ENGINE is not set
#
-# DMA Clients
+# USB Gadget Support
#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
#
-# DMA Devices
+# LED drivers
#
#
-# Auxiliary Display support
+# LED Triggers
#
+# CONFIG_LEDS_TRIGGERS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_AUXDISPLAY is not set
#
-# Virtualization
+# Userspace I/O
#
+# CONFIG_UIO is not set
#
# File systems
#
CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
# CONFIG_EXT3_FS_SECURITY is not set
# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
@@ -1082,13 +1154,16 @@ CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
#
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
# CONFIG_UDF_FS is not set
#
@@ -1100,22 +1175,21 @@ CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_NTFS_FS=y
-# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_DEBUG=y
CONFIG_NTFS_RW=y
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
+# CONFIG_PROC_KCORE is not set
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -1133,19 +1207,16 @@ CONFIG_CONFIGFS_FS=m
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
+# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
+# CONFIG_NFSD_V4 is not set
CONFIG_NFSD_TCP=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
@@ -1153,25 +1224,20 @@ CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
@@ -1191,13 +1257,13 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
-CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -1208,44 +1274,39 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
+CONFIG_NLS_UTF8=y
# CONFIG_DLM is not set
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
+# CONFIG_INSTRUMENTATION is not set
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
-# CONFIG_UNUSED_SYMBOLS is not set
-CONFIG_DEBUG_FS=y
+CONFIG_UNUSED_SYMBOLS=y
+# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_SLUB_DEBUG_ON is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1253,16 +1314,21 @@ CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
# CONFIG_FRAME_POINTER is not set
-CONFIG_FORCED_INLINING=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
-CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_BOOTMEM is not set
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_4KSTACKS is not set
+# CONFIG_IRQSTACKS is not set
# CONFIG_SH_KGDB is not set
#
@@ -1270,16 +1336,11 @@ CONFIG_DEBUG_STACKOVERFLOW=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1290,10 +1351,12 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
@@ -1306,15 +1369,14 @@ CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_HW=y
#
# Library routines
@@ -1322,7 +1384,11 @@ CONFIG_CRYPTO_DES=y
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
index a5e37dbc5353..240a1cef69aa 100644
--- a/arch/sh/configs/se7712_defconfig
+++ b/arch/sh/configs/se7712_defconfig
@@ -237,7 +237,7 @@ CONFIG_CPU_HAS_SR_RB=y
CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=16
# CONFIG_NO_IDLE_HZ is not set
-CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_SH_PCLK_FREQ=66666666
#
# CPU Frequency scaling
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 4e711a0c3dae..01936368b8b0 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -12,7 +12,7 @@ config SH_DMA
config NR_ONCHIP_DMA_CHANNELS
int
depends on SH_DMA
- default "6" if CPU_SUBTYPE_SH7720
+ default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
default "12" if CPU_SUBTYPE_SH7780
default "4"
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index 958bac1c585a..5c3359756a92 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -25,6 +25,7 @@ static int dmte_irq_map[] = {
DMTE2_IRQ,
DMTE3_IRQ,
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
defined(CONFIG_CPU_SUBTYPE_SH7760) || \
defined(CONFIG_CPU_SUBTYPE_SH7709) || \
@@ -203,6 +204,7 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)
}
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7780)
#define dmaor_read_reg() ctrl_inw(DMAOR)
#define dmaor_write_reg(data) ctrl_outw(data, DMAOR)
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index fba6b5ba0b3a..0718805774e8 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -7,16 +7,19 @@ obj-$(CONFIG_PCI_AUTO) += pci-auto.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7763) += pci-sh7780.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o
+obj-$(CONFIG_CPU_SH5) += pci-sh5.o ops-sh5.o
-obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \
- dma-dreamcast.o
+obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o
obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o
obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o
obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o
obj-$(CONFIG_SH_HIGHLANDER) += ops-r7780rp.o fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7780) += ops-sdk7780.o fixups-sdk7780.o
obj-$(CONFIG_SH_TITAN) += ops-titan.o
obj-$(CONFIG_SH_LANDISK) += ops-landisk.o
obj-$(CONFIG_SH_LBOX_RE2) += ops-lboxre2.o fixups-lboxre2.o
obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += ops-se7780.o fixups-se7780.o
+obj-$(CONFIG_SH_CAYMAN) += ops-cayman.o
diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
deleted file mode 100644
index 888a34050599..000000000000
--- a/arch/sh/drivers/pci/dma-dreamcast.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * arch/sh/drivers/pci/dma-dreamcast.c
- *
- * PCI DMA support for the Sega Dreamcast
- *
- * Copyright (C) 2001, 2002 M. R. Brown
- * Copyright (C) 2002, 2003 Paul Mundt
- *
- * This file originally bore the message (with enclosed-$):
- * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
- * Dreamcast PCI: Supports SEGA Broadband Adaptor only.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-
-static int gapspci_dma_used = 0;
-
-void *dreamcast_consistent_alloc(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- unsigned long buf;
-
- if (dev && dev->bus != &pci_bus_type)
- return NULL;
-
- if (gapspci_dma_used + size > GAPSPCI_DMA_SIZE)
- return ERR_PTR(-EINVAL);
-
- buf = GAPSPCI_DMA_BASE + gapspci_dma_used;
-
- gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
-
- *dma_handle = (dma_addr_t)buf;
-
- buf = P2SEGADDR(buf);
-
- /* Flush the dcache before we hand off the buffer */
- __flush_purge_region((void *)buf, size);
-
- return (void *)buf;
-}
-
-int dreamcast_consistent_free(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- if (dev && dev->bus != &pci_bus_type)
- return -EINVAL;
-
- /* XXX */
- gapspci_dma_used = 0;
-
- return 0;
-}
-
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index 6f53f8200dc3..c44699301eeb 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -40,6 +41,15 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
*/
dev->resource[1].start = p->io_resource->start + 0x100;
dev->resource[1].end = dev->resource[1].start + 0x200 - 1;
+ /*
+ * Redirect dma memory allocations to special memory window.
+ */
+ BUG_ON(!dma_declare_coherent_memory(&dev->dev,
+ GAPSPCI_DMA_BASE,
+ GAPSPCI_DMA_BASE,
+ GAPSPCI_DMA_SIZE,
+ DMA_MEMORY_MAP |
+ DMA_MEMORY_EXCLUSIVE));
break;
default:
printk("PCI: Failed resource fixup\n");
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
new file mode 100644
index 000000000000..2f8863099dd1
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -0,0 +1,59 @@
+/*
+ * arch/sh/drivers/pci/fixups-sdk7780.c
+ *
+ * PCI fixups for the SDK7780SE03
+ *
+ * Copyright (C) 2003 Lineo uSolutions, Inc.
+ * Copyright (C) 2004 - 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/pci.h>
+#include "pci-sh4.h"
+#include <asm/io.h>
+
+int pci_fixup_pcic(void)
+{
+ ctrl_outl(0x00000001, SH7780_PCI_VCR2);
+
+ /* Enable all interrupts, so we know what to fix */
+ pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
+ pci_write_reg(0x0000380F, SH7780_PCIAINTM);
+
+ /* Set up standard PCI config registers */
+ pci_write_reg(0xFB00, SH7780_PCISTATUS);
+ pci_write_reg(0x0047, SH7780_PCICMD);
+ pci_write_reg(0x00, SH7780_PCIPIF);
+ pci_write_reg(0x00, SH7780_PCISUB);
+ pci_write_reg(0x06, SH7780_PCIBCC);
+ pci_write_reg(0x1912, SH7780_PCISVID);
+ pci_write_reg(0x0001, SH7780_PCISID);
+
+ pci_write_reg(0x08000000, SH7780_PCIMBAR0); /* PCI */
+ pci_write_reg(0x08000000, SH7780_PCILAR0); /* SHwy */
+ pci_write_reg(0x07F00001, SH7780_PCILSR); /* size 128M w/ MBAR */
+
+ pci_write_reg(0x00000000, SH7780_PCIMBAR1);
+ pci_write_reg(0x00000000, SH7780_PCILAR1);
+ pci_write_reg(0x00000000, SH7780_PCILSR1);
+
+ pci_write_reg(0xAB000801, SH7780_PCIIBAR);
+
+ /*
+ * Set the MBR so PCI address is one-to-one with window,
+ * meaning all calls go straight through... use ifdef to
+ * catch erroneous assumption.
+ */
+ pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
+ pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0); /* 16M */
+
+ /* Set IOBR for window containing area specified in pci.h */
+ pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR);
+ pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR);
+
+ pci_write_reg(0xA5000C01, SH7780_PCICR);
+
+ return 0;
+}
diff --git a/arch/sh/drivers/pci/ops-cayman.c b/arch/sh/drivers/pci/ops-cayman.c
new file mode 100644
index 000000000000..980275ffa30b
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-cayman.c
@@ -0,0 +1,94 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <asm/cpu/irq.h>
+#include "pci-sh5.h"
+
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+ return (((pin - 1) + slot) % 4) + 1;
+}
+
+int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int result = -1;
+
+ /* The complication here is that the PCI IRQ lines from the Cayman's 2
+ 5V slots get into the CPU via a different path from the IRQ lines
+ from the 3 3.3V slots. Thus, we have to detect whether the card's
+ interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling'
+ at the point where we cross from 5V to 3.3V is not the normal case.
+
+ The added complication is that we don't know that the 5V slots are
+ always bus 2, because a card containing a PCI-PCI bridge may be
+ plugged into a 3.3V slot, and this changes the bus numbering.
+
+ Also, the Cayman has an intermediate PCI bus that goes a custom
+ expansion board header (and to the secondary bridge). This bus has
+ never been used in practice.
+
+ The 1ary onboard PCI-PCI bridge is device 3 on bus 0
+ The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of
+ the 1ary bridge.
+ */
+
+ struct slot_pin {
+ int slot;
+ int pin;
+ } path[4];
+ int i=0;
+
+ while (dev->bus->number > 0) {
+
+ slot = path[i].slot = PCI_SLOT(dev->devfn);
+ pin = path[i].pin = bridge_swizzle(pin, slot);
+ dev = dev->bus->self;
+ i++;
+ if (i > 3) panic("PCI path to root bus too long!\n");
+ }
+
+ slot = PCI_SLOT(dev->devfn);
+ /* This is the slot on bus 0 through which the device is eventually
+ reachable. */
+
+ /* Now work back up. */
+ if ((slot < 3) || (i == 0)) {
+ /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
+ swizzle now. */
+ result = IRQ_INTA + bridge_swizzle(pin, slot) - 1;
+ } else {
+ i--;
+ slot = path[i].slot;
+ pin = path[i].pin;
+ if (slot > 0) {
+ panic("PCI expansion bus device found - not handled!\n");
+ } else {
+ if (i > 0) {
+ /* 5V slots */
+ i--;
+ slot = path[i].slot;
+ pin = path[i].pin;
+ /* 'pin' was swizzled earlier wrt slot, don't do it again. */
+ result = IRQ_P2INTA + (pin - 1);
+ } else {
+ /* IRQ for 2ary PCI-PCI bridge : unused */
+ result = -1;
+ }
+ }
+ }
+
+ return result;
+}
+
+struct pci_channel board_pci_channels[] = {
+ { &sh5_pci_ops, NULL, NULL, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+int __init pcibios_init_platform(void)
+{
+ return sh5pci_init(__pa(memory_start),
+ __pa(memory_end) - __pa(memory_start));
+}
diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
index 48fe4032ebea..5fdadaeed6fc 100644
--- a/arch/sh/drivers/pci/ops-r7780rp.c
+++ b/arch/sh/drivers/pci/ops-r7780rp.c
@@ -17,25 +17,13 @@
#include <asm/io.h>
#include "pci-sh4.h"
-static char r7780rp_irq_tab[] __initdata = {
- 0, 1, 2, 3,
-};
-
-static char r7780mp_irq_tab[] __initdata = {
+static char irq_tab[] __initdata = {
65, 66, 67, 68,
};
int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
- if (mach_is_r7780rp())
- return r7780rp_irq_tab[slot];
- if (mach_is_r7780mp() || mach_is_r7785rp())
- return r7780mp_irq_tab[slot];
-
- printk(KERN_ERR "PCI: Bad IRQ mapping "
- "request for slot %d, func %d\n", slot, pin-1);
-
- return -1;
+ return irq_tab[slot];
}
static struct resource sh7780_io_resource = {
diff --git a/arch/sh/drivers/pci/ops-sdk7780.c b/arch/sh/drivers/pci/ops-sdk7780.c
new file mode 100644
index 000000000000..66a9b4047f26
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-sdk7780.c
@@ -0,0 +1,73 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-sdk7780.c
+ *
+ * Copyright (C) 2006 Nobuhiro Iwamatsu
+ *
+ * PCI initialization for the SDK7780SE03
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/sdk7780.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
+
+/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
+static char sdk7780_irq_tab[4][16] __initdata = {
+ /* INTA */
+ { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTB */
+ { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTC */
+ { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTD */
+ { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ return sdk7780_irq_tab[pin-1][slot];
+}
+
+static struct resource sdk7780_io_resource = {
+ .name = "SH7780_IO",
+ .start = SH7780_PCI_IO_BASE,
+ .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sdk7780_mem_resource = {
+ .name = "SH7780_mem",
+ .start = SH7780_PCI_MEMORY_BASE,
+ .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+struct pci_channel board_pci_channels[] = {
+ { &sh4_pci_ops, &sdk7780_io_resource, &sdk7780_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map sdk7780_pci_map = {
+ .window0 = {
+ .base = SH7780_CS2_BASE_ADDR,
+ .size = 0x04000000,
+ },
+ .window1 = {
+ .base = SH7780_CS3_BASE_ADDR,
+ .size = 0x04000000,
+ },
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ printk(KERN_INFO "SH7780 PCI: Finished initializing PCI controller\n");
+ return sh7780_pcic_init(&sdk7780_pci_map);
+}
diff --git a/arch/sh/drivers/pci/ops-sh5.c b/arch/sh/drivers/pci/ops-sh5.c
new file mode 100644
index 000000000000..729e38a6fe07
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-sh5.c
@@ -0,0 +1,93 @@
+/*
+ * Support functions for the SH5 PCI hardware.
+ *
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003, 2004 Paul Mundt
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+#include <linux/kernel.h>
+#include <linux/rwsem.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include "pci-sh5.h"
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+ int i;
+
+ /*
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
+ */
+ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ printk("PCI: IDE base address fixup for %s\n", pci_name(d));
+ for(i=0; i<4; i++) {
+ struct resource *r = &d->resource[i];
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+
+char * __devinit pcibios_setup(char *str)
+{
+ return str;
+}
+
+static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *val)
+{
+ SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+
+ switch (size) {
+ case 1:
+ *val = (u8)SH5PCI_READ_BYTE(PDR + (where & 3));
+ break;
+ case 2:
+ *val = (u16)SH5PCI_READ_SHORT(PDR + (where & 2));
+ break;
+ case 4:
+ *val = SH5PCI_READ(PDR);
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int sh5pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+
+ switch (size) {
+ case 1:
+ SH5PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
+ break;
+ case 2:
+ SH5PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
+ break;
+ case 4:
+ SH5PCI_WRITE(PDR, val);
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sh5_pci_ops = {
+ .read = sh5pci_read,
+ .write = sh5pci_write,
+};
diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
index 224e007736fb..ea404704ace8 100644
--- a/arch/sh/drivers/pci/pci-auto.c
+++ b/arch/sh/drivers/pci/pci-auto.c
@@ -516,10 +516,8 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
PCI_COMMAND, cmdstat | PCI_COMMAND_IO |
PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_LATENCY_TIMER, 0x80);
-#endif
/* Allocate PCI I/O and/or memory space */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5);
diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
index 1901c33cde6a..4925c79ea959 100644
--- a/arch/sh/drivers/pci/pci-sh4.h
+++ b/arch/sh/drivers/pci/pci-sh4.h
@@ -1,7 +1,9 @@
#ifndef __PCI_SH4_H
#define __PCI_SH4_H
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7763)
#include "pci-sh7780.h"
#else
#include "pci-sh7751.h"
diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c
new file mode 100644
index 000000000000..a00a4df8c02d
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh5.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003, 2004 Paul Mundt
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Support functions for the SH5 PCI hardware.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rwsem.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <asm/cpu/irq.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include "pci-sh5.h"
+
+unsigned long pcicr_virt;
+unsigned long PCI_IO_AREA;
+
+/* Rounds a number UP to the nearest power of two. Used for
+ * sizing the PCI window.
+ */
+static u32 __init r2p2(u32 num)
+{
+ int i = 31;
+ u32 tmp = num;
+
+ if (num == 0)
+ return 0;
+
+ do {
+ if (tmp & (1 << 31))
+ break;
+ i--;
+ tmp <<= 1;
+ } while (i >= 0);
+
+ tmp = 1 << i;
+ /* If the original number isn't a power of 2, round it up */
+ if (tmp != num)
+ tmp <<= 1;
+
+ return tmp;
+}
+
+static irqreturn_t pcish5_err_irq(int irq, void *dev_id)
+{
+ struct pt_regs *regs = get_irq_regs();
+ unsigned pci_int, pci_air, pci_cir, pci_aint;
+
+ pci_int = SH5PCI_READ(INT);
+ pci_cir = SH5PCI_READ(CIR);
+ pci_air = SH5PCI_READ(AIR);
+
+ if (pci_int) {
+ printk("PCI INTERRUPT (at %08llx)!\n", regs->pc);
+ printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
+ printk("PCI AIR -> 0x%x\n", pci_air);
+ printk("PCI CIR -> 0x%x\n", pci_cir);
+ SH5PCI_WRITE(INT, ~0);
+ }
+
+ pci_aint = SH5PCI_READ(AINT);
+ if (pci_aint) {
+ printk("PCI ARB INTERRUPT!\n");
+ printk("PCI AINT -> 0x%x\n", pci_aint);
+ printk("PCI AIR -> 0x%x\n", pci_air);
+ printk("PCI CIR -> 0x%x\n", pci_cir);
+ SH5PCI_WRITE(AINT, ~0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
+{
+ printk("SERR IRQ\n");
+
+ return IRQ_NONE;
+}
+
+int __init sh5pci_init(unsigned long memStart, unsigned long memSize)
+{
+ u32 lsr0;
+ u32 uval;
+
+ if (request_irq(IRQ_ERR, pcish5_err_irq,
+ IRQF_DISABLED, "PCI Error",NULL) < 0) {
+ printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n");
+ return -EINVAL;
+ }
+
+ if (request_irq(IRQ_SERR, pcish5_serr_irq,
+ IRQF_DISABLED, "PCI SERR interrupt", NULL) < 0) {
+ printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n");
+ return -EINVAL;
+ }
+
+ pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");
+ if (!pcicr_virt) {
+ panic("Unable to remap PCICR\n");
+ }
+
+ PCI_IO_AREA = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");
+ if (!PCI_IO_AREA) {
+ panic("Unable to remap PCIIO\n");
+ }
+
+ /* Clear snoop registers */
+ SH5PCI_WRITE(CSCR0, 0);
+ SH5PCI_WRITE(CSCR1, 0);
+
+ /* Switch off interrupts */
+ SH5PCI_WRITE(INTM, 0);
+ SH5PCI_WRITE(AINTM, 0);
+ SH5PCI_WRITE(PINTM, 0);
+
+ /* Set bus active, take it out of reset */
+ uval = SH5PCI_READ(CR);
+
+ /* Set command Register */
+ SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE |
+ CR_PFCS | CR_BMAM);
+
+ uval=SH5PCI_READ(CR);
+
+ /* Allow it to be a master */
+ /* NB - WE DISABLE I/O ACCESS to stop overlap */
+ /* set WAIT bit to enable stepping, an attempt to improve stability */
+ SH5PCI_WRITE_SHORT(CSR_CMD,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_WAIT);
+
+ /*
+ ** Set translation mapping memory in order to convert the address
+ ** used for the main bus, to the PCI internal address.
+ */
+ SH5PCI_WRITE(MBR,0x40000000);
+
+ /* Always set the max size 512M */
+ SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));
+
+ /*
+ ** I/O addresses are mapped at internal PCI specific address
+ ** as is described into the configuration bridge table.
+ ** These are changed to 0, to allow cards that have legacy
+ ** io such as vga to function correctly. We set the SH5 IOBAR to
+ ** 256K, which is a bit big as we can only have 64K of address space
+ */
+
+ SH5PCI_WRITE(IOBR,0x0);
+
+ /* Set up a 256K window. Totally pointless waste of address space */
+ SH5PCI_WRITE(IOBMR,0);
+
+ /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
+ * Ideally, we would want to map the I/O region somewhere, but it
+ * is so big this is not that easy!
+ */
+ SH5PCI_WRITE(CSR_IBAR0,~0);
+ /* Set memory size value */
+ memSize = memory_end - memory_start;
+
+ /* Now we set up the mbars so the PCI bus can see the memory of
+ * the machine */
+ if (memSize < (1024 * 1024)) {
+ printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%lx?\n",
+ memSize);
+ return -EINVAL;
+ }
+
+ /* Set LSR 0 */
+ lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 :
+ ((r2p2(memSize) - 0x100000) | 0x1);
+ SH5PCI_WRITE(LSR0, lsr0);
+
+ /* Set MBAR 0 */
+ SH5PCI_WRITE(CSR_MBAR0, memory_start);
+ SH5PCI_WRITE(LAR0, memory_start);
+
+ SH5PCI_WRITE(CSR_MBAR1,0);
+ SH5PCI_WRITE(LAR1,0);
+ SH5PCI_WRITE(LSR1,0);
+
+ /* Enable the PCI interrupts on the device */
+ SH5PCI_WRITE(INTM, ~0);
+ SH5PCI_WRITE(AINTM, ~0);
+ SH5PCI_WRITE(PINTM, ~0);
+
+ return 0;
+}
+
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct pci_dev *dev = bus->self;
+ int i;
+
+ if (dev) {
+ for (i= 0; i < 3; i++) {
+ bus->resource[i] =
+ &dev->resource[PCI_BRIDGE_RESOURCES+i];
+ bus->resource[i]->name = bus->name;
+ }
+ bus->resource[0]->flags |= IORESOURCE_IO;
+ bus->resource[1]->flags |= IORESOURCE_MEM;
+
+ /* For now, propagate host limits to the bus;
+ * we'll adjust them later. */
+ bus->resource[0]->end = 64*1024 - 1 ;
+ bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1;
+ bus->resource[0]->start = PCIBIOS_MIN_IO;
+ bus->resource[1]->start = PCIBIOS_MIN_MEM;
+
+ /* Turn off downstream PF memory address range by default */
+ bus->resource[2]->start = 1024*1024;
+ bus->resource[2]->end = bus->resource[2]->start - 1;
+ }
+}
diff --git a/arch/sh/drivers/pci/pci-sh5.h b/arch/sh/drivers/pci/pci-sh5.h
new file mode 100644
index 000000000000..7cff3fc04d30
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh5.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Definitions for the SH5 PCI hardware.
+ */
+#ifndef __PCI_SH5_H
+#define __PCI_SH5_H
+
+/* Product ID */
+#define PCISH5_PID 0x350d
+
+/* vendor ID */
+#define PCISH5_VID 0x1054
+
+/* Configuration types */
+#define ST_TYPE0 0x00 /* Configuration cycle type 0 */
+#define ST_TYPE1 0x01 /* Configuration cycle type 1 */
+
+/* VCR data */
+#define PCISH5_VCR_STATUS 0x00
+#define PCISH5_VCR_VERSION 0x08
+
+/*
+** ICR register offsets and bits
+*/
+#define PCISH5_ICR_CR 0x100 /* PCI control register values */
+#define CR_PBAM (1<<12)
+#define CR_PFCS (1<<11)
+#define CR_FTO (1<<10)
+#define CR_PFE (1<<9)
+#define CR_TBS (1<<8)
+#define CR_SPUE (1<<7)
+#define CR_BMAM (1<<6)
+#define CR_HOST (1<<5)
+#define CR_CLKEN (1<<4)
+#define CR_SOCS (1<<3)
+#define CR_IOCS (1<<2)
+#define CR_RSTCTL (1<<1)
+#define CR_CFINT (1<<0)
+#define CR_LOCK_MASK 0xa5000000
+
+#define PCISH5_ICR_INT 0x114 /* Interrupt registert values */
+#define INT_MADIM (1<<2)
+
+#define PCISH5_ICR_LSR0 0X104 /* Local space register values */
+#define PCISH5_ICR_LSR1 0X108 /* Local space register values */
+#define PCISH5_ICR_LAR0 0x10c /* Local address register values */
+#define PCISH5_ICR_LAR1 0x110 /* Local address register values */
+#define PCISH5_ICR_INTM 0x118 /* Interrupt mask register values */
+#define PCISH5_ICR_AIR 0x11c /* Interrupt error address information register values */
+#define PCISH5_ICR_CIR 0x120 /* Interrupt error command information register values */
+#define PCISH5_ICR_AINT 0x130 /* Interrupt error arbiter interrupt register values */
+#define PCISH5_ICR_AINTM 0x134 /* Interrupt error arbiter interrupt mask register values */
+#define PCISH5_ICR_BMIR 0x138 /* Interrupt error info register of bus master values */
+#define PCISH5_ICR_PAR 0x1c0 /* Pio address register values */
+#define PCISH5_ICR_MBR 0x1c4 /* Memory space bank register values */
+#define PCISH5_ICR_IOBR 0x1c8 /* I/O space bank register values */
+#define PCISH5_ICR_PINT 0x1cc /* power management interrupt register values */
+#define PCISH5_ICR_PINTM 0x1d0 /* power management interrupt mask register values */
+#define PCISH5_ICR_MBMR 0x1d8 /* memory space bank mask register values */
+#define PCISH5_ICR_IOBMR 0x1dc /* I/O space bank mask register values */
+#define PCISH5_ICR_CSCR0 0x210 /* PCI cache snoop control register 0 */
+#define PCISH5_ICR_CSCR1 0x214 /* PCI cache snoop control register 1 */
+#define PCISH5_ICR_PDR 0x220 /* Pio data register values */
+
+/* These are configs space registers */
+#define PCISH5_ICR_CSR_VID 0x000 /* Vendor id */
+#define PCISH5_ICR_CSR_DID 0x002 /* Device id */
+#define PCISH5_ICR_CSR_CMD 0x004 /* Command register */
+#define PCISH5_ICR_CSR_STATUS 0x006 /* Stautus */
+#define PCISH5_ICR_CSR_IBAR0 0x010 /* I/O base address register */
+#define PCISH5_ICR_CSR_MBAR0 0x014 /* First Memory base address register */
+#define PCISH5_ICR_CSR_MBAR1 0x018 /* Second Memory base address register */
+
+/* Base address of registers */
+#define SH5PCI_ICR_BASE (PHYS_PCI_BLOCK + 0x00040000)
+#define SH5PCI_IO_BASE (PHYS_PCI_BLOCK + 0x00800000)
+/* #define SH5PCI_VCR_BASE (P2SEG_PCICB_BLOCK + P2SEG) */
+
+extern unsigned long pcicr_virt;
+/* Register selection macro */
+#define PCISH5_ICR_REG(x) ( pcicr_virt + (PCISH5_ICR_##x))
+/* #define PCISH5_VCR_REG(x) ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */
+
+/* Write I/O functions */
+#define SH5PCI_WRITE(reg,val) ctrl_outl((u32)(val),PCISH5_ICR_REG(reg))
+#define SH5PCI_WRITE_SHORT(reg,val) ctrl_outw((u16)(val),PCISH5_ICR_REG(reg))
+#define SH5PCI_WRITE_BYTE(reg,val) ctrl_outb((u8)(val),PCISH5_ICR_REG(reg))
+
+/* Read I/O functions */
+#define SH5PCI_READ(reg) ctrl_inl(PCISH5_ICR_REG(reg))
+#define SH5PCI_READ_SHORT(reg) ctrl_inw(PCISH5_ICR_REG(reg))
+#define SH5PCI_READ_BYTE(reg) ctrl_inb(PCISH5_ICR_REG(reg))
+
+/* Set PCI config bits */
+#define SET_CONFIG_BITS(bus,devfn,where) ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000)
+
+/* Set PCI command register */
+#define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where)
+
+/* Size converters */
+#define PCISH5_MEM_SIZCONV(x) (((x / 0x40000) - 1) << 18)
+#define PCISH5_IO_SIZCONV(x) (((x / 0x40000) - 1) << 18)
+
+extern struct pci_ops sh5_pci_ops;
+
+/* arch/sh/drivers/pci/pci-sh5.c */
+int sh5pci_init(unsigned long memStart, unsigned long memSize);
+
+#endif /* __PCI_SH5_H */
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index e516087fb435..7d797f4de5e7 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -58,6 +58,7 @@ static int __init sh7780_pci_init(void)
id = pci_read_reg(SH7780_PCIVID);
if ((id & 0xffff) == SH7780_VENDOR_ID) {
switch ((id >> 16) & 0xffff) {
+ case SH7763_DEVICE_ID:
case SH7780_DEVICE_ID:
case SH7781_DEVICE_ID:
case SH7785_DEVICE_ID:
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
index 1d069a859de2..97b2c98f05c4 100644
--- a/arch/sh/drivers/pci/pci-sh7780.h
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -16,6 +16,7 @@
#define SH7780_VENDOR_ID 0x1912
#define SH7781_DEVICE_ID 0x0001
#define SH7780_DEVICE_ID 0x0002
+#define SH7763_DEVICE_ID 0x0004
#define SH7785_DEVICE_ID 0x0007
/* SH7780 Control Registers */
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index ccaba368ac9b..49b435c3a57a 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -71,7 +71,7 @@ subsys_initcall(pcibios_init);
* Called after each bus is probed, but before its children
* are examined.
*/
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus)
{
pci_read_bridge_bases(bus);
}
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 4b81d9c47b00..349d833deab5 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -1,25 +1,5 @@
-#
-# Makefile for the Linux/SuperH kernel.
-#
-
-extra-y := head.o init_task.o vmlinux.lds
-
-obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \
- semaphore.o setup.o signal.o sys_sh.o syscalls.o \
- time.o topology.o traps.o
-
-obj-y += cpu/ timers/
-obj-$(CONFIG_VSYSCALL) += vsyscall/
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
-obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
-obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
-obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
-obj-$(CONFIG_MODULES) += sh_ksyms.o module.o
-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
-obj-$(CONFIG_PM) += pm.o
-obj-$(CONFIG_STACKTRACE) += stacktrace.o
-
-EXTRA_CFLAGS += -Werror
+ifeq ($(CONFIG_SUPERH32),y)
+include ${srctree}/arch/sh/kernel/Makefile_32
+else
+include ${srctree}/arch/sh/kernel/Makefile_64
+endif
diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
new file mode 100644
index 000000000000..c89289831053
--- /dev/null
+++ b/arch/sh/kernel/Makefile_32
@@ -0,0 +1,26 @@
+#
+# Makefile for the Linux/SuperH kernel.
+#
+
+extra-y := head_32.o init_task.o vmlinux.lds
+
+obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \
+ ptrace_32.o semaphore.o setup.o signal_32.o sys_sh.o sys_sh32.o \
+ syscalls_32.o time_32.o topology.o traps.o traps_32.o
+
+obj-y += cpu/ timers/
+obj-$(CONFIG_VSYSCALL) += vsyscall/
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
+obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
+obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_MODULES) += sh_ksyms_32.o module.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_BINFMT_ELF) += dump_task.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64
new file mode 100644
index 000000000000..1ef21cc087f3
--- /dev/null
+++ b/arch/sh/kernel/Makefile_64
@@ -0,0 +1,22 @@
+extra-y := head_64.o init_task.o vmlinux.lds
+
+obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_64.o \
+ ptrace_64.o semaphore.o setup.o signal_64.o sys_sh.o sys_sh64.o \
+ syscalls_64.o time_64.o topology.o traps.o traps_64.o
+
+obj-y += cpu/ timers/
+obj-$(CONFIG_VSYSCALL) += vsyscall/
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
+obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
+obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_MODULES) += sh_ksyms_64.o module.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_BINFMT_ELF) += dump_task.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index d055a3ea6b4b..f471d242774e 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -6,8 +6,14 @@ obj-$(CONFIG_CPU_SH2) = sh2/
obj-$(CONFIG_CPU_SH2A) = sh2a/
obj-$(CONFIG_CPU_SH3) = sh3/
obj-$(CONFIG_CPU_SH4) = sh4/
+obj-$(CONFIG_CPU_SH5) = sh5/
+
+# Special cases for family ancestry.
+
obj-$(CONFIG_CPU_SH4A) += sh4a/
+# Common interfaces.
+
obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index c217c4bf0085..80a31329ead9 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/log2.h>
#include <asm/mmu_context.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
@@ -20,9 +21,12 @@
#include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>
+#include <asm/elf.h>
#include <asm/io.h>
-#include <asm/ubc.h>
#include <asm/smp.h>
+#ifdef CONFIG_SUPERH32
+#include <asm/ubc.h>
+#endif
/*
* Generic wrapper for command line arguments to disable on-chip
@@ -61,25 +65,12 @@ static void __init speculative_execution_init(void)
/*
* Generic first-level cache init
*/
-static void __init cache_init(void)
+#ifdef CONFIG_SUPERH32
+static void __uses_jump_to_uncached cache_init(void)
{
unsigned long ccr, flags;
- /* First setup the rest of the I-cache info */
- current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr -
- current_cpu_data.icache.linesz;
-
- current_cpu_data.icache.way_size = current_cpu_data.icache.sets *
- current_cpu_data.icache.linesz;
-
- /* And the D-cache too */
- current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr -
- current_cpu_data.dcache.linesz;
-
- current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
- current_cpu_data.dcache.linesz;
-
- jump_to_P2();
+ jump_to_uncached();
ccr = ctrl_inl(CCR);
/*
@@ -156,7 +147,31 @@ static void __init cache_init(void)
#endif
ctrl_outl(flags, CCR);
- back_to_P1();
+ back_to_cached();
+}
+#else
+#define cache_init() do { } while (0)
+#endif
+
+#define CSHAPE(totalsize, linesize, assoc) \
+ ((totalsize & ~0xff) | (linesize << 4) | assoc)
+
+#define CACHE_DESC_SHAPE(desc) \
+ CSHAPE((desc).way_size * (desc).ways, ilog2((desc).linesz), (desc).ways)
+
+static void detect_cache_shape(void)
+{
+ l1d_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.dcache);
+
+ if (current_cpu_data.dcache.flags & SH_CACHE_COMBINED)
+ l1i_cache_shape = l1d_cache_shape;
+ else
+ l1i_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.icache);
+
+ if (current_cpu_data.flags & CPU_HAS_L2_CACHE)
+ l2_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.scache);
+ else
+ l2_cache_shape = -1; /* No S-cache */
}
#ifdef CONFIG_SH_DSP
@@ -228,14 +243,32 @@ asmlinkage void __cpuinit sh_cpu_init(void)
if (current_cpu_data.type == CPU_SH_NONE)
panic("Unknown CPU");
+ /* First setup the rest of the I-cache info */
+ current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr -
+ current_cpu_data.icache.linesz;
+
+ current_cpu_data.icache.way_size = current_cpu_data.icache.sets *
+ current_cpu_data.icache.linesz;
+
+ /* And the D-cache too */
+ current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr -
+ current_cpu_data.dcache.linesz;
+
+ current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
+ current_cpu_data.dcache.linesz;
+
/* Init the cache */
cache_init();
- if (raw_smp_processor_id() == 0)
+ if (raw_smp_processor_id() == 0) {
shm_align_mask = max_t(unsigned long,
current_cpu_data.dcache.way_size - 1,
PAGE_SIZE - 1);
+ /* Boot CPU sets the cache shape */
+ detect_cache_shape();
+ }
+
/* Disable the FPU */
if (fpu_disabled) {
printk("FPU Disabled\n");
@@ -273,7 +306,10 @@ asmlinkage void __cpuinit sh_cpu_init(void)
* like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
* we wake it up and hope that all is well.
*/
+#ifdef CONFIG_SUPERH32
if (raw_smp_processor_id() == 0)
ubc_wakeup();
+#endif
+
speculative_execution_init();
}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 8da8e178f09c..cc1836e47a5d 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -1,7 +1,9 @@
#
# Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
#
-obj-y += imask.o intc.o
+obj-y += intc.o
+obj-$(CONFIG_SUPERH32) += imask.o
+obj-$(CONFIG_CPU_SH5) += intc-sh5.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c
new file mode 100644
index 000000000000..43ee7a9a4f0b
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq/intc-sh5.c
@@ -0,0 +1,257 @@
+/*
+ * arch/sh/kernel/cpu/irq/intc-sh5.c
+ *
+ * Interrupt Controller support for SH5 INTC.
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 Paul Mundt
+ *
+ * Per-interrupt selective. IRLM=0 (Fixed priority) is not
+ * supported being useless without a cascaded interrupt
+ * controller.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <asm/cpu/irq.h>
+#include <asm/page.h>
+
+/*
+ * Maybe the generic Peripheral block could move to a more
+ * generic include file. INTC Block will be defined here
+ * and only here to make INTC self-contained in a single
+ * file.
+ */
+#define INTC_BLOCK_OFFSET 0x01000000
+
+/* Base */
+#define INTC_BASE PHYS_PERIPHERAL_BLOCK + \
+ INTC_BLOCK_OFFSET
+
+/* Address */
+#define INTC_ICR_SET (intc_virt + 0x0)
+#define INTC_ICR_CLEAR (intc_virt + 0x8)
+#define INTC_INTPRI_0 (intc_virt + 0x10)
+#define INTC_INTSRC_0 (intc_virt + 0x50)
+#define INTC_INTSRC_1 (intc_virt + 0x58)
+#define INTC_INTREQ_0 (intc_virt + 0x60)
+#define INTC_INTREQ_1 (intc_virt + 0x68)
+#define INTC_INTENB_0 (intc_virt + 0x70)
+#define INTC_INTENB_1 (intc_virt + 0x78)
+#define INTC_INTDSB_0 (intc_virt + 0x80)
+#define INTC_INTDSB_1 (intc_virt + 0x88)
+
+#define INTC_ICR_IRLM 0x1
+#define INTC_INTPRI_PREGS 8 /* 8 Priority Registers */
+#define INTC_INTPRI_PPREG 8 /* 8 Priorities per Register */
+
+
+/*
+ * Mapper between the vector ordinal and the IRQ number
+ * passed to kernel/device drivers.
+ */
+int intc_evt_to_irq[(0xE20/0x20)+1] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0x000 - 0x0E0 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0x100 - 0x1E0 */
+ 0, 0, 0, 0, 0, 1, 0, 0, /* 0x200 - 0x2E0 */
+ 2, 0, 0, 3, 0, 0, 0, -1, /* 0x300 - 0x3E0 */
+ 32, 33, 34, 35, 36, 37, 38, -1, /* 0x400 - 0x4E0 */
+ -1, -1, -1, 63, -1, -1, -1, -1, /* 0x500 - 0x5E0 */
+ -1, -1, 18, 19, 20, 21, 22, -1, /* 0x600 - 0x6E0 */
+ 39, 40, 41, 42, -1, -1, -1, -1, /* 0x700 - 0x7E0 */
+ 4, 5, 6, 7, -1, -1, -1, -1, /* 0x800 - 0x8E0 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0x900 - 0x9E0 */
+ 12, 13, 14, 15, 16, 17, -1, -1, /* 0xA00 - 0xAE0 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB00 - 0xBE0 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC00 - 0xCE0 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD00 - 0xDE0 */
+ -1, -1 /* 0xE00 - 0xE20 */
+};
+
+/*
+ * Opposite mapper.
+ */
+static int IRQ_to_vectorN[NR_INTC_IRQS] = {
+ 0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /* 0- 7 */
+ -1, -1, -1, -1, 0x50, 0x51, 0x52, 0x53, /* 8-15 */
+ 0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36, -1, /* 16-23 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */
+ 0x39, 0x3A, 0x3B, -1, -1, -1, -1, -1, /* 40-47 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 48-55 */
+ -1, -1, -1, -1, -1, -1, -1, 0x2B, /* 56-63 */
+
+};
+
+static unsigned long intc_virt;
+
+static unsigned int startup_intc_irq(unsigned int irq);
+static void shutdown_intc_irq(unsigned int irq);
+static void enable_intc_irq(unsigned int irq);
+static void disable_intc_irq(unsigned int irq);
+static void mask_and_ack_intc(unsigned int);
+static void end_intc_irq(unsigned int irq);
+
+static struct hw_interrupt_type intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .enable = enable_intc_irq,
+ .disable = disable_intc_irq,
+ .ack = mask_and_ack_intc,
+ .end = end_intc_irq
+};
+
+static int irlm; /* IRL mode */
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static void enable_intc_irq(unsigned int irq)
+{
+ unsigned long reg;
+ unsigned long bitmask;
+
+ if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY))
+ printk("Trying to use straight IRL0-3 with an encoding platform.\n");
+
+ if (irq < 32) {
+ reg = INTC_INTENB_0;
+ bitmask = 1 << irq;
+ } else {
+ reg = INTC_INTENB_1;
+ bitmask = 1 << (irq - 32);
+ }
+
+ ctrl_outl(bitmask, reg);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ unsigned long reg;
+ unsigned long bitmask;
+
+ if (irq < 32) {
+ reg = INTC_INTDSB_0;
+ bitmask = 1 << irq;
+ } else {
+ reg = INTC_INTDSB_1;
+ bitmask = 1 << (irq - 32);
+ }
+
+ ctrl_outl(bitmask, reg);
+}
+
+static void mask_and_ack_intc(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+}
+
+/* For future use, if we ever support IRLM=0) */
+void make_intc_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].chip = &intc_irq_type;
+ disable_intc_irq(irq);
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+int intc_irq_describe(char* p, int irq)
+{
+ if (irq < NR_INTC_IRQS)
+ return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20);
+ else
+ return 0;
+}
+#endif
+
+void __init plat_irq_setup(void)
+{
+ unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
+ unsigned long reg;
+ unsigned long data;
+ int i;
+
+ intc_virt = onchip_remap(INTC_BASE, 1024, "INTC");
+ if (!intc_virt) {
+ panic("Unable to remap INTC\n");
+ }
+
+
+ /* Set default: per-line enable/disable, priority driven ack/eoi */
+ for (i = 0; i < NR_INTC_IRQS; i++) {
+ if (platform_int_priority[i] != NO_PRIORITY) {
+ irq_desc[i].chip = &intc_irq_type;
+ }
+ }
+
+
+ /* Disable all interrupts and set all priorities to 0 to avoid trouble */
+ ctrl_outl(-1, INTC_INTDSB_0);
+ ctrl_outl(-1, INTC_INTDSB_1);
+
+ for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8)
+ ctrl_outl( NO_PRIORITY, reg);
+
+
+ /* Set IRLM */
+ /* If all the priorities are set to 'no priority', then
+ * assume we are using encoded mode.
+ */
+ irlm = platform_int_priority[IRQ_IRL0] + platform_int_priority[IRQ_IRL1] + \
+ platform_int_priority[IRQ_IRL2] + platform_int_priority[IRQ_IRL3];
+
+ if (irlm == NO_PRIORITY) {
+ /* IRLM = 0 */
+ reg = INTC_ICR_CLEAR;
+ i = IRQ_INTA;
+ printk("Trying to use encoded IRL0-3. IRLs unsupported.\n");
+ } else {
+ /* IRLM = 1 */
+ reg = INTC_ICR_SET;
+ i = IRQ_IRL0;
+ }
+ ctrl_outl(INTC_ICR_IRLM, reg);
+
+ /* Set interrupt priorities according to platform description */
+ for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) {
+ data |= platform_int_priority[i] << ((i % INTC_INTPRI_PPREG) * 4);
+ if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) {
+ /* Upon the 7th, set Priority Register */
+ ctrl_outl(data, reg);
+ data = 0;
+ reg += 8;
+ }
+ }
+
+ /*
+ * And now let interrupts come in.
+ * sti() is not enough, we need to
+ * lower priority, too.
+ */
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+}
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 6ac018c15e03..84806b2027f8 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -335,31 +335,6 @@ static intc_enum __init intc_grp_id(struct intc_desc *desc,
return 0;
}
-static unsigned int __init intc_prio_value(struct intc_desc *desc,
- intc_enum enum_id, int do_grps)
-{
- struct intc_prio *p = desc->priorities;
- unsigned int i;
-
- for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
- p = desc->priorities + i;
-
- if (p->enum_id != enum_id)
- continue;
-
- return p->priority;
- }
-
- if (do_grps)
- return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
-
- /* default to the lowest priority possible if no priority is set
- * - this needs to be at least 2 for 5-bit priorities on 7780
- */
-
- return 2;
-}
-
static unsigned int __init intc_mask_data(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id, int do_grps)
@@ -518,8 +493,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
handle_level_irq, "level");
set_irq_chip_data(irq, (void *)data[primary]);
- /* record the desired priority level */
- intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1);
+ /* set priority level
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+ intc_prio_level[irq] = 2;
/* enable secondary masking method if present */
if (data[!primary])
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index ee8f1fe84b08..7a26569e7956 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -149,6 +149,14 @@ ENTRY(exception_handler)
mov #32,r8
cmp/hs r8,r9
bt trap_entry ! 64 > vec >= 32 is trap
+
+#if defined(CONFIG_SH_FPU)
+ mov #13,r8
+ cmp/eq r8,r9
+ bt 10f ! fpu
+ nop
+#endif
+
mov.l 4f,r8
mov r9,r4
shll2 r9
@@ -158,6 +166,10 @@ ENTRY(exception_handler)
cmp/eq r9,r8
bf 3f
mov.l 8f,r8 ! unhandled exception
+#if defined(CONFIG_SH_FPU)
+10:
+ mov.l 9f, r8 ! unhandled exception
+#endif
3:
mov.l 5f,r10
jmp @r8
@@ -177,7 +189,10 @@ interrupt_entry:
6: .long ret_from_irq
7: .long do_IRQ
8: .long do_exception_error
-
+#ifdef CONFIG_SH_FPU
+9: .long fpu_error_trap_handler
+#endif
+
trap_entry:
mov #0x30,r8
cmp/ge r8,r9 ! vector 0x20-0x2f is systemcall
@@ -250,7 +265,7 @@ ENTRY(sh_bios_handler)
1: .long gdb_vbr_vector
#endif /* CONFIG_SH_STANDARD_BIOS */
-ENTRY(address_error_handler)
+ENTRY(address_error_trap_handler)
mov r15,r4 ! regs
add #4,r4
mov #OFF_PC,r0
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index ec6adc3f306f..b230eb278cef 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -65,7 +65,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups,
- NULL, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct plat_sci_port sci_platform_data[] = {
{
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 965fa2572b23..b279cdc3a233 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -6,4 +6,8 @@ obj-y := common.o probe.o opcode_helper.o
common-y += $(addprefix ../sh2/, ex.o entry.o)
+obj-$(CONFIG_SH_FPU) += fpu.o
+
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7203) += setup-sh7203.o clock-sh7203.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7263) += setup-sh7203.o clock-sh7203.o
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
new file mode 100644
index 000000000000..3feb95a4fcbc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
@@ -0,0 +1,89 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7203.c
+ *
+ * SH7203 support for the clock framework
+ *
+ * Copyright (C) 2007 Kieran Bingham (MPC-Data Ltd)
+ *
+ * Based on clock-sh7263.c
+ * Copyright (C) 2006 Yoshinori Sato
+ *
+ * Based on clock-sh4.c
+ * Copyright (C) 2005 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+const static int pll1rate[]={8,12,16,0};
+const static int pfc_divisors[]={1,2,3,4,6,8,12};
+#define ifc_divisors pfc_divisors
+
+#if (CONFIG_SH_CLK_MD == 0)
+#define PLL2 (1)
+#elif (CONFIG_SH_CLK_MD == 1)
+#define PLL2 (2)
+#elif (CONFIG_SH_CLK_MD == 2)
+#define PLL2 (4)
+#elif (CONFIG_SH_CLK_MD == 3)
+#define PLL2 (4)
+#else
+#error "Illegal Clock Mode!"
+#endif
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0003] * PLL2 ;
+}
+
+static struct clk_ops sh7203_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inw(FREQCR) & 0x0007);
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7203_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inw(FREQCR) & 0x0007);
+ clk->rate = clk->parent->rate / pfc_divisors[idx-2];
+}
+
+static struct clk_ops sh7203_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ clk->rate = clk->parent->rate;
+}
+
+static struct clk_ops sh7203_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7203_clk_ops[] = {
+ &sh7203_master_clk_ops,
+ &sh7203_module_clk_ops,
+ &sh7203_bus_clk_ops,
+ &sh7203_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7203_clk_ops))
+ *ops = sh7203_clk_ops[idx];
+}
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c
new file mode 100644
index 000000000000..ff99562456fb
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/fpu.c
@@ -0,0 +1,633 @@
+/*
+ * Save/restore floating point context for signal handlers.
+ *
+ * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * FIXME! These routines can be optimized in big endian case.
+ */
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+/* The PR (precision) bit in the FP Status Register must be clear when
+ * an frchg instruction is executed, otherwise the instruction is undefined.
+ * Executing frchg with PR set causes a trap on some SH4 implementations.
+ */
+
+#define FPSCR_RCHG 0x00000000
+
+
+/*
+ * Save FPU registers onto task structure.
+ * Assume called with FPU enabled (SR.FD=0).
+ */
+void
+save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+ unsigned long dummy;
+
+ clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+ enable_fpu();
+ asm volatile("sts.l fpul, @-%0\n\t"
+ "sts.l fpscr, @-%0\n\t"
+ "fmov.s fr15, @-%0\n\t"
+ "fmov.s fr14, @-%0\n\t"
+ "fmov.s fr13, @-%0\n\t"
+ "fmov.s fr12, @-%0\n\t"
+ "fmov.s fr11, @-%0\n\t"
+ "fmov.s fr10, @-%0\n\t"
+ "fmov.s fr9, @-%0\n\t"
+ "fmov.s fr8, @-%0\n\t"
+ "fmov.s fr7, @-%0\n\t"
+ "fmov.s fr6, @-%0\n\t"
+ "fmov.s fr5, @-%0\n\t"
+ "fmov.s fr4, @-%0\n\t"
+ "fmov.s fr3, @-%0\n\t"
+ "fmov.s fr2, @-%0\n\t"
+ "fmov.s fr1, @-%0\n\t"
+ "fmov.s fr0, @-%0\n\t"
+ "lds %3, fpscr\n\t"
+ : "=r" (dummy)
+ : "0" ((char *)(&tsk->thread.fpu.hard.status)),
+ "r" (FPSCR_RCHG),
+ "r" (FPSCR_INIT)
+ : "memory");
+
+ disable_fpu();
+ release_fpu(regs);
+}
+
+static void
+restore_fpu(struct task_struct *tsk)
+{
+ unsigned long dummy;
+
+ enable_fpu();
+ asm volatile("fmov.s @%0+, fr0\n\t"
+ "fmov.s @%0+, fr1\n\t"
+ "fmov.s @%0+, fr2\n\t"
+ "fmov.s @%0+, fr3\n\t"
+ "fmov.s @%0+, fr4\n\t"
+ "fmov.s @%0+, fr5\n\t"
+ "fmov.s @%0+, fr6\n\t"
+ "fmov.s @%0+, fr7\n\t"
+ "fmov.s @%0+, fr8\n\t"
+ "fmov.s @%0+, fr9\n\t"
+ "fmov.s @%0+, fr10\n\t"
+ "fmov.s @%0+, fr11\n\t"
+ "fmov.s @%0+, fr12\n\t"
+ "fmov.s @%0+, fr13\n\t"
+ "fmov.s @%0+, fr14\n\t"
+ "fmov.s @%0+, fr15\n\t"
+ "lds.l @%0+, fpscr\n\t"
+ "lds.l @%0+, fpul\n\t"
+ : "=r" (dummy)
+ : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
+ : "memory");
+ disable_fpu();
+}
+
+/*
+ * Load the FPU with signalling NANS. This bit pattern we're using
+ * has the property that no matter wether considered as single or as
+ * double precission represents signaling NANS.
+ */
+
+static void
+fpu_init(void)
+{
+ enable_fpu();
+ asm volatile("lds %0, fpul\n\t"
+ "fsts fpul, fr0\n\t"
+ "fsts fpul, fr1\n\t"
+ "fsts fpul, fr2\n\t"
+ "fsts fpul, fr3\n\t"
+ "fsts fpul, fr4\n\t"
+ "fsts fpul, fr5\n\t"
+ "fsts fpul, fr6\n\t"
+ "fsts fpul, fr7\n\t"
+ "fsts fpul, fr8\n\t"
+ "fsts fpul, fr9\n\t"
+ "fsts fpul, fr10\n\t"
+ "fsts fpul, fr11\n\t"
+ "fsts fpul, fr12\n\t"
+ "fsts fpul, fr13\n\t"
+ "fsts fpul, fr14\n\t"
+ "fsts fpul, fr15\n\t"
+ "lds %2, fpscr\n\t"
+ : /* no output */
+ : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
+ disable_fpu();
+}
+
+/*
+ * Emulate arithmetic ops on denormalized number for some FPU insns.
+ */
+
+/* denormalized float * float */
+static int denormal_mulf(int hx, int hy)
+{
+ unsigned int ix, iy;
+ unsigned long long m, n;
+ int exp, w;
+
+ ix = hx & 0x7fffffff;
+ iy = hy & 0x7fffffff;
+ if (iy < 0x00800000 || ix == 0)
+ return ((hx ^ hy) & 0x80000000);
+
+ exp = (iy & 0x7f800000) >> 23;
+ ix &= 0x007fffff;
+ iy = (iy & 0x007fffff) | 0x00800000;
+ m = (unsigned long long)ix * iy;
+ n = m;
+ w = -1;
+ while (n) { n >>= 1; w++; }
+
+ /* FIXME: use guard bits */
+ exp += w - 126 - 46;
+ if (exp > 0)
+ ix = ((int) (m >> (w - 23)) & 0x007fffff) | (exp << 23);
+ else if (exp + 22 >= 0)
+ ix = (int) (m >> (w - 22 - exp)) & 0x007fffff;
+ else
+ ix = 0;
+
+ ix |= (hx ^ hy) & 0x80000000;
+ return ix;
+}
+
+/* denormalized double * double */
+static void mult64(unsigned long long x, unsigned long long y,
+ unsigned long long *highp, unsigned long long *lowp)
+{
+ unsigned long long sub0, sub1, sub2, sub3;
+ unsigned long long high, low;
+
+ sub0 = (x >> 32) * (unsigned long) (y >> 32);
+ sub1 = (x & 0xffffffffLL) * (unsigned long) (y >> 32);
+ sub2 = (x >> 32) * (unsigned long) (y & 0xffffffffLL);
+ sub3 = (x & 0xffffffffLL) * (unsigned long) (y & 0xffffffffLL);
+ low = sub3;
+ high = 0LL;
+ sub3 += (sub1 << 32);
+ if (low > sub3)
+ high++;
+ low = sub3;
+ sub3 += (sub2 << 32);
+ if (low > sub3)
+ high++;
+ low = sub3;
+ high += (sub1 >> 32) + (sub2 >> 32);
+ high += sub0;
+ *lowp = low;
+ *highp = high;
+}
+
+static inline long long rshift64(unsigned long long mh,
+ unsigned long long ml, int n)
+{
+ if (n >= 64)
+ return mh >> (n - 64);
+ return (mh << (64 - n)) | (ml >> n);
+}
+
+static long long denormal_muld(long long hx, long long hy)
+{
+ unsigned long long ix, iy;
+ unsigned long long mh, ml, nh, nl;
+ int exp, w;
+
+ ix = hx & 0x7fffffffffffffffLL;
+ iy = hy & 0x7fffffffffffffffLL;
+ if (iy < 0x0010000000000000LL || ix == 0)
+ return ((hx ^ hy) & 0x8000000000000000LL);
+
+ exp = (iy & 0x7ff0000000000000LL) >> 52;
+ ix &= 0x000fffffffffffffLL;
+ iy = (iy & 0x000fffffffffffffLL) | 0x0010000000000000LL;
+ mult64(ix, iy, &mh, &ml);
+ nh = mh;
+ nl = ml;
+ w = -1;
+ if (nh) {
+ while (nh) { nh >>= 1; w++;}
+ w += 64;
+ } else
+ while (nl) { nl >>= 1; w++;}
+
+ /* FIXME: use guard bits */
+ exp += w - 1022 - 52 * 2;
+ if (exp > 0)
+ ix = (rshift64(mh, ml, w - 52) & 0x000fffffffffffffLL)
+ | ((long long)exp << 52);
+ else if (exp + 51 >= 0)
+ ix = rshift64(mh, ml, w - 51 - exp) & 0x000fffffffffffffLL;
+ else
+ ix = 0;
+
+ ix |= (hx ^ hy) & 0x8000000000000000LL;
+ return ix;
+}
+
+/* ix - iy where iy: denormal and ix, iy >= 0 */
+static int denormal_subf1(unsigned int ix, unsigned int iy)
+{
+ int frac;
+ int exp;
+
+ if (ix < 0x00800000)
+ return ix - iy;
+
+ exp = (ix & 0x7f800000) >> 23;
+ if (exp - 1 > 31)
+ return ix;
+ iy >>= exp - 1;
+ if (iy == 0)
+ return ix;
+
+ frac = (ix & 0x007fffff) | 0x00800000;
+ frac -= iy;
+ while (frac < 0x00800000) {
+ if (--exp == 0)
+ return frac;
+ frac <<= 1;
+ }
+
+ return (exp << 23) | (frac & 0x007fffff);
+}
+
+/* ix + iy where iy: denormal and ix, iy >= 0 */
+static int denormal_addf1(unsigned int ix, unsigned int iy)
+{
+ int frac;
+ int exp;
+
+ if (ix < 0x00800000)
+ return ix + iy;
+
+ exp = (ix & 0x7f800000) >> 23;
+ if (exp - 1 > 31)
+ return ix;
+ iy >>= exp - 1;
+ if (iy == 0)
+ return ix;
+
+ frac = (ix & 0x007fffff) | 0x00800000;
+ frac += iy;
+ if (frac >= 0x01000000) {
+ frac >>= 1;
+ ++exp;
+ }
+
+ return (exp << 23) | (frac & 0x007fffff);
+}
+
+static int denormal_addf(int hx, int hy)
+{
+ unsigned int ix, iy;
+ int sign;
+
+ if ((hx ^ hy) & 0x80000000) {
+ sign = hx & 0x80000000;
+ ix = hx & 0x7fffffff;
+ iy = hy & 0x7fffffff;
+ if (iy < 0x00800000) {
+ ix = denormal_subf1(ix, iy);
+ if (ix < 0) {
+ ix = -ix;
+ sign ^= 0x80000000;
+ }
+ } else {
+ ix = denormal_subf1(iy, ix);
+ sign ^= 0x80000000;
+ }
+ } else {
+ sign = hx & 0x80000000;
+ ix = hx & 0x7fffffff;
+ iy = hy & 0x7fffffff;
+ if (iy < 0x00800000)
+ ix = denormal_addf1(ix, iy);
+ else
+ ix = denormal_addf1(iy, ix);
+ }
+
+ return sign | ix;
+}
+
+/* ix - iy where iy: denormal and ix, iy >= 0 */
+static long long denormal_subd1(unsigned long long ix, unsigned long long iy)
+{
+ long long frac;
+ int exp;
+
+ if (ix < 0x0010000000000000LL)
+ return ix - iy;
+
+ exp = (ix & 0x7ff0000000000000LL) >> 52;
+ if (exp - 1 > 63)
+ return ix;
+ iy >>= exp - 1;
+ if (iy == 0)
+ return ix;
+
+ frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
+ frac -= iy;
+ while (frac < 0x0010000000000000LL) {
+ if (--exp == 0)
+ return frac;
+ frac <<= 1;
+ }
+
+ return ((long long)exp << 52) | (frac & 0x000fffffffffffffLL);
+}
+
+/* ix + iy where iy: denormal and ix, iy >= 0 */
+static long long denormal_addd1(unsigned long long ix, unsigned long long iy)
+{
+ long long frac;
+ long long exp;
+
+ if (ix < 0x0010000000000000LL)
+ return ix + iy;
+
+ exp = (ix & 0x7ff0000000000000LL) >> 52;
+ if (exp - 1 > 63)
+ return ix;
+ iy >>= exp - 1;
+ if (iy == 0)
+ return ix;
+
+ frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
+ frac += iy;
+ if (frac >= 0x0020000000000000LL) {
+ frac >>= 1;
+ ++exp;
+ }
+
+ return (exp << 52) | (frac & 0x000fffffffffffffLL);
+}
+
+static long long denormal_addd(long long hx, long long hy)
+{
+ unsigned long long ix, iy;
+ long long sign;
+
+ if ((hx ^ hy) & 0x8000000000000000LL) {
+ sign = hx & 0x8000000000000000LL;
+ ix = hx & 0x7fffffffffffffffLL;
+ iy = hy & 0x7fffffffffffffffLL;
+ if (iy < 0x0010000000000000LL) {
+ ix = denormal_subd1(ix, iy);
+ if (ix < 0) {
+ ix = -ix;
+ sign ^= 0x8000000000000000LL;
+ }
+ } else {
+ ix = denormal_subd1(iy, ix);
+ sign ^= 0x8000000000000000LL;
+ }
+ } else {
+ sign = hx & 0x8000000000000000LL;
+ ix = hx & 0x7fffffffffffffffLL;
+ iy = hy & 0x7fffffffffffffffLL;
+ if (iy < 0x0010000000000000LL)
+ ix = denormal_addd1(ix, iy);
+ else
+ ix = denormal_addd1(iy, ix);
+ }
+
+ return sign | ix;
+}
+
+/**
+ * denormal_to_double - Given denormalized float number,
+ * store double float
+ *
+ * @fpu: Pointer to sh_fpu_hard structure
+ * @n: Index to FP register
+ */
+static void
+denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+{
+ unsigned long du, dl;
+ unsigned long x = fpu->fpul;
+ int exp = 1023 - 126;
+
+ if (x != 0 && (x & 0x7f800000) == 0) {
+ du = (x & 0x80000000);
+ while ((x & 0x00800000) == 0) {
+ x <<= 1;
+ exp--;
+ }
+ x &= 0x007fffff;
+ du |= (exp << 20) | (x >> 3);
+ dl = x << 29;
+
+ fpu->fp_regs[n] = du;
+ fpu->fp_regs[n+1] = dl;
+ }
+}
+
+/**
+ * ieee_fpe_handler - Handle denormalized number exception
+ *
+ * @regs: Pointer to register structure
+ *
+ * Returns 1 when it's handled (should not cause exception).
+ */
+static int
+ieee_fpe_handler (struct pt_regs *regs)
+{
+ unsigned short insn = *(unsigned short *) regs->pc;
+ unsigned short finsn;
+ unsigned long nextpc;
+ int nib[4] = {
+ (insn >> 12) & 0xf,
+ (insn >> 8) & 0xf,
+ (insn >> 4) & 0xf,
+ insn & 0xf};
+
+ if (nib[0] == 0xb ||
+ (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
+ regs->pr = regs->pc + 4;
+ if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
+ nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
+ if (regs->sr & 1)
+ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+ else
+ nextpc = regs->pc + 4;
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
+ if (regs->sr & 1)
+ nextpc = regs->pc + 4;
+ else
+ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x4 && nib[3] == 0xb &&
+ (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
+ nextpc = regs->regs[nib[1]];
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x0 && nib[3] == 0x3 &&
+ (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
+ nextpc = regs->pc + 4 + regs->regs[nib[1]];
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (insn == 0x000b) { /* rts */
+ nextpc = regs->pr;
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else {
+ nextpc = regs->pc + 2;
+ finsn = insn;
+ }
+
+#define FPSCR_FPU_ERROR (1 << 17)
+
+ if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
+ struct task_struct *tsk = current;
+
+ if ((tsk->thread.fpu.hard.fpscr & FPSCR_FPU_ERROR)) {
+ /* FPU error */
+ denormal_to_double (&tsk->thread.fpu.hard,
+ (finsn >> 8) & 0xf);
+ } else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ } else if ((finsn & 0xf00f) == 0xf002) { /* fmul */
+ struct task_struct *tsk = current;
+ int fpscr;
+ int n, m, prec;
+ unsigned int hx, hy;
+
+ n = (finsn >> 8) & 0xf;
+ m = (finsn >> 4) & 0xf;
+ hx = tsk->thread.fpu.hard.fp_regs[n];
+ hy = tsk->thread.fpu.hard.fp_regs[m];
+ fpscr = tsk->thread.fpu.hard.fpscr;
+ prec = fpscr & (1 << 19);
+
+ if ((fpscr & FPSCR_FPU_ERROR)
+ && (prec && ((hx & 0x7fffffff) < 0x00100000
+ || (hy & 0x7fffffff) < 0x00100000))) {
+ long long llx, lly;
+
+ /* FPU error because of denormal */
+ llx = ((long long) hx << 32)
+ | tsk->thread.fpu.hard.fp_regs[n+1];
+ lly = ((long long) hy << 32)
+ | tsk->thread.fpu.hard.fp_regs[m+1];
+ if ((hx & 0x7fffffff) >= 0x00100000)
+ llx = denormal_muld(lly, llx);
+ else
+ llx = denormal_muld(llx, lly);
+ tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
+ tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
+ } else if ((fpscr & FPSCR_FPU_ERROR)
+ && (!prec && ((hx & 0x7fffffff) < 0x00800000
+ || (hy & 0x7fffffff) < 0x00800000))) {
+ /* FPU error because of denormal */
+ if ((hx & 0x7fffffff) >= 0x00800000)
+ hx = denormal_mulf(hy, hx);
+ else
+ hx = denormal_mulf(hx, hy);
+ tsk->thread.fpu.hard.fp_regs[n] = hx;
+ } else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ } else if ((finsn & 0xf00e) == 0xf000) { /* fadd, fsub */
+ struct task_struct *tsk = current;
+ int fpscr;
+ int n, m, prec;
+ unsigned int hx, hy;
+
+ n = (finsn >> 8) & 0xf;
+ m = (finsn >> 4) & 0xf;
+ hx = tsk->thread.fpu.hard.fp_regs[n];
+ hy = tsk->thread.fpu.hard.fp_regs[m];
+ fpscr = tsk->thread.fpu.hard.fpscr;
+ prec = fpscr & (1 << 19);
+
+ if ((fpscr & FPSCR_FPU_ERROR)
+ && (prec && ((hx & 0x7fffffff) < 0x00100000
+ || (hy & 0x7fffffff) < 0x00100000))) {
+ long long llx, lly;
+
+ /* FPU error because of denormal */
+ llx = ((long long) hx << 32)
+ | tsk->thread.fpu.hard.fp_regs[n+1];
+ lly = ((long long) hy << 32)
+ | tsk->thread.fpu.hard.fp_regs[m+1];
+ if ((finsn & 0xf00f) == 0xf000)
+ llx = denormal_addd(llx, lly);
+ else
+ llx = denormal_addd(llx, lly ^ (1LL << 63));
+ tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
+ tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
+ } else if ((fpscr & FPSCR_FPU_ERROR)
+ && (!prec && ((hx & 0x7fffffff) < 0x00800000
+ || (hy & 0x7fffffff) < 0x00800000))) {
+ /* FPU error because of denormal */
+ if ((finsn & 0xf00f) == 0xf000)
+ hx = denormal_addf(hx, hy);
+ else
+ hx = denormal_addf(hx, hy ^ 0x80000000);
+ tsk->thread.fpu.hard.fp_regs[n] = hx;
+ } else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ }
+
+ return 0;
+}
+
+BUILD_TRAP_HANDLER(fpu_error)
+{
+ struct task_struct *tsk = current;
+ TRAP_HANDLER_DECL;
+
+ save_fpu(tsk, regs);
+ if (ieee_fpe_handler(regs)) {
+ tsk->thread.fpu.hard.fpscr &=
+ ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+ grab_fpu(regs);
+ restore_fpu(tsk);
+ set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ return;
+ }
+
+ force_sig(SIGFPE, tsk);
+}
+
+BUILD_TRAP_HANDLER(fpu_state_restore)
+{
+ struct task_struct *tsk = current;
+ TRAP_HANDLER_DECL;
+
+ grab_fpu(regs);
+ if (!user_mode(regs)) {
+ printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
+ return;
+ }
+
+ if (used_math()) {
+ /* Using the FPU again. */
+ restore_fpu(tsk);
+ } else {
+ /* First time FPU user. */
+ fpu_init();
+ set_used_math();
+ }
+ set_tsk_thread_flag(tsk, TIF_USEDFPU);
+}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 6d02465704b9..6910e2664468 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -3,25 +3,36 @@
*
* CPU Subtype Probing for SH-2A.
*
- * Copyright (C) 2004, 2005 Paul Mundt
+ * Copyright (C) 2004 - 2007 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-
#include <linux/init.h>
#include <asm/processor.h>
#include <asm/cache.h>
int __init detect_cpu_and_cache_system(void)
{
- /* Just SH7206 for now .. */
- boot_cpu_data.type = CPU_SH7206;
+ /* All SH-2A CPUs have support for 16 and 32-bit opcodes.. */
boot_cpu_data.flags |= CPU_HAS_OP32;
+#if defined(CONFIG_CPU_SUBTYPE_SH7203)
+ boot_cpu_data.type = CPU_SH7203;
+ /* SH7203 has an FPU.. */
+ boot_cpu_data.flags |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7263)
+ boot_cpu_data.type = CPU_SH7263;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+ boot_cpu_data.type = CPU_SH7206;
+ /* While SH7206 has a DSP.. */
+ boot_cpu_data.flags |= CPU_HAS_DSP;
+#endif
+
boot_cpu_data.dcache.ways = 4;
- boot_cpu_data.dcache.way_incr = (1 << 11);
+ boot_cpu_data.dcache.way_incr = (1 << 11);
boot_cpu_data.dcache.sets = 128;
boot_cpu_data.dcache.entry_shift = 4;
boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
@@ -37,4 +48,3 @@ int __init detect_cpu_and_cache_system(void)
return 0;
}
-
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
new file mode 100644
index 000000000000..db6ef5cecde1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -0,0 +1,319 @@
+/*
+ * SH7203 and SH7263 Setup
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+ DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
+ DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
+ DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
+ DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
+ USB, LCDC, CMT0, CMT1, BSC, WDT,
+ MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
+ MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
+ MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
+ MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
+ MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
+ MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
+ ADC_ADI,
+ IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI,
+ IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI,
+ IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI,
+ IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI, IIC33_TEI,
+ SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+ SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+ SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+ SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+ SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI,
+ SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI,
+ SSI0_SSII, SSI1_SSII, SSI2_SSII, SSI3_SSII,
+
+ /* ROM-DEC, SDHI, SRC, and IEB are SH7263 specific */
+ ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG, ROMDEC_ISEC, ROMDEC_IBUF,
+ ROMDEC_IREADY,
+
+ FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+
+ SDHI3, SDHI0, SDHI1,
+
+ RTC_ARM, RTC_PRD, RTC_CUP,
+ RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1, RCAN0_SLE,
+ RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1, RCAN1_SLE,
+
+ SRC_OVF, SRC_ODFI, SRC_IDEI, IEBI,
+
+ /* interrupt groups */
+ PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+ MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU4_ABCD,
+ IIC30, IIC31, IIC32, IIC33, SCIF0, SCIF1, SCIF2, SCIF3,
+ SSU0, SSU1, ROMDEC, SDHI, FLCTL, RTC, RCAN0, RCAN1, SRC
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+ INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+ INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+ INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+ INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+ INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+ INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+ INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+ INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
+ INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
+ INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
+ INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
+ INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
+ INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
+ INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
+ INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
+ INTC_IRQ(USB, 140), INTC_IRQ(LCDC, 141),
+ INTC_IRQ(CMT0, 142), INTC_IRQ(CMT1, 143),
+ INTC_IRQ(BSC, 144), INTC_IRQ(WDT, 145),
+ INTC_IRQ(MTU2_TGI0A, 146), INTC_IRQ(MTU2_TGI0B, 147),
+ INTC_IRQ(MTU2_TGI0C, 148), INTC_IRQ(MTU2_TGI0D, 149),
+ INTC_IRQ(MTU2_TCI0V, 150),
+ INTC_IRQ(MTU2_TGI0E, 151), INTC_IRQ(MTU2_TGI0F, 152),
+ INTC_IRQ(MTU2_TGI1A, 153), INTC_IRQ(MTU2_TGI1B, 154),
+ INTC_IRQ(MTU2_TCI1V, 155), INTC_IRQ(MTU2_TCI1U, 156),
+ INTC_IRQ(MTU2_TGI2A, 157), INTC_IRQ(MTU2_TGI2B, 158),
+ INTC_IRQ(MTU2_TCI2V, 159), INTC_IRQ(MTU2_TCI2U, 160),
+ INTC_IRQ(MTU2_TGI3A, 161), INTC_IRQ(MTU2_TGI3B, 162),
+ INTC_IRQ(MTU2_TGI3C, 163), INTC_IRQ(MTU2_TGI3D, 164),
+ INTC_IRQ(MTU2_TCI3V, 165),
+ INTC_IRQ(MTU2_TGI4A, 166), INTC_IRQ(MTU2_TGI4B, 167),
+ INTC_IRQ(MTU2_TGI4C, 168), INTC_IRQ(MTU2_TGI4D, 169),
+ INTC_IRQ(MTU2_TCI4V, 170),
+ INTC_IRQ(ADC_ADI, 171),
+ INTC_IRQ(IIC30_STPI, 172), INTC_IRQ(IIC30_NAKI, 173),
+ INTC_IRQ(IIC30_RXI, 174), INTC_IRQ(IIC30_TXI, 175),
+ INTC_IRQ(IIC30_TEI, 176),
+ INTC_IRQ(IIC31_STPI, 177), INTC_IRQ(IIC31_NAKI, 178),
+ INTC_IRQ(IIC31_RXI, 179), INTC_IRQ(IIC31_TXI, 180),
+ INTC_IRQ(IIC31_TEI, 181),
+ INTC_IRQ(IIC32_STPI, 182), INTC_IRQ(IIC32_NAKI, 183),
+ INTC_IRQ(IIC32_RXI, 184), INTC_IRQ(IIC32_TXI, 185),
+ INTC_IRQ(IIC32_TEI, 186),
+ INTC_IRQ(IIC33_STPI, 187), INTC_IRQ(IIC33_NAKI, 188),
+ INTC_IRQ(IIC33_RXI, 189), INTC_IRQ(IIC33_TXI, 190),
+ INTC_IRQ(IIC33_TEI, 191),
+ INTC_IRQ(SCIF0_BRI, 192), INTC_IRQ(SCIF0_ERI, 193),
+ INTC_IRQ(SCIF0_RXI, 194), INTC_IRQ(SCIF0_TXI, 195),
+ INTC_IRQ(SCIF1_BRI, 196), INTC_IRQ(SCIF1_ERI, 197),
+ INTC_IRQ(SCIF1_RXI, 198), INTC_IRQ(SCIF1_TXI, 199),
+ INTC_IRQ(SCIF2_BRI, 200), INTC_IRQ(SCIF2_ERI, 201),
+ INTC_IRQ(SCIF2_RXI, 202), INTC_IRQ(SCIF2_TXI, 203),
+ INTC_IRQ(SCIF3_BRI, 204), INTC_IRQ(SCIF3_ERI, 205),
+ INTC_IRQ(SCIF3_RXI, 206), INTC_IRQ(SCIF3_TXI, 207),
+ INTC_IRQ(SSU0_SSERI, 208), INTC_IRQ(SSU0_SSRXI, 209),
+ INTC_IRQ(SSU0_SSTXI, 210),
+ INTC_IRQ(SSU1_SSERI, 211), INTC_IRQ(SSU1_SSRXI, 212),
+ INTC_IRQ(SSU1_SSTXI, 213),
+ INTC_IRQ(SSI0_SSII, 214), INTC_IRQ(SSI1_SSII, 215),
+ INTC_IRQ(SSI2_SSII, 216), INTC_IRQ(SSI3_SSII, 217),
+ INTC_IRQ(FLCTL_FLSTEI, 224), INTC_IRQ(FLCTL_FLTENDI, 225),
+ INTC_IRQ(FLCTL_FLTREQ0I, 226), INTC_IRQ(FLCTL_FLTREQ1I, 227),
+ INTC_IRQ(RTC_ARM, 231), INTC_IRQ(RTC_PRD, 232),
+ INTC_IRQ(RTC_CUP, 233),
+ INTC_IRQ(RCAN0_ERS, 234), INTC_IRQ(RCAN0_OVR, 235),
+ INTC_IRQ(RCAN0_RM0, 236), INTC_IRQ(RCAN0_RM1, 237),
+ INTC_IRQ(RCAN0_SLE, 238),
+ INTC_IRQ(RCAN1_ERS, 239), INTC_IRQ(RCAN1_OVR, 240),
+ INTC_IRQ(RCAN1_RM0, 241), INTC_IRQ(RCAN1_RM1, 242),
+ INTC_IRQ(RCAN1_SLE, 243),
+
+ /* SH7263-specific trash */
+#ifdef CONFIG_CPU_SUBTYPE_SH7263
+ INTC_IRQ(ROMDEC_ISY, 218), INTC_IRQ(ROMDEC_IERR, 219),
+ INTC_IRQ(ROMDEC_IARG, 220), INTC_IRQ(ROMDEC_ISEC, 221),
+ INTC_IRQ(ROMDEC_IBUF, 222), INTC_IRQ(ROMDEC_IREADY, 223),
+
+ INTC_IRQ(SDHI3, 228), INTC_IRQ(SDHI0, 229), INTC_IRQ(SDHI1, 230),
+
+ INTC_IRQ(SRC_OVF, 244), INTC_IRQ(SRC_ODFI, 245),
+ INTC_IRQ(SRC_IDEI, 246),
+
+ INTC_IRQ(IEBI, 247),
+#endif
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+ PINT4, PINT5, PINT6, PINT7),
+ INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
+ INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
+ INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
+ INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
+ INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
+ INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
+ INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
+ INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
+ INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
+ INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
+ INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
+ INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
+ INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
+ INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
+ INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
+ INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
+ INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI,
+ IIC30_TEI),
+ INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI,
+ IIC31_TEI),
+ INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI,
+ IIC32_TEI),
+ INTC_GROUP(IIC33, IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI,
+ IIC33_TEI),
+ INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+ INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+ INTC_GROUP(SSU0, SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI),
+ INTC_GROUP(SSU1, SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI),
+ INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I,
+ FLCTL_FLTREQ1I),
+ INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP),
+ INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1,
+ RCAN0_SLE),
+ INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1,
+ RCAN1_SLE),
+
+#ifdef CONFIG_CPU_SUBTYPE_SH7263
+ INTC_GROUP(ROMDEC, ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG,
+ ROMDEC_ISEC, ROMDEC_IBUF, ROMDEC_IREADY),
+ INTC_GROUP(SDHI, SDHI3, SDHI0, SDHI1),
+ INTC_GROUP(SRC, SRC_OVF, SRC_ODFI, SRC_IDEI),
+#endif
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+ { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+ { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
+ { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { USB, LCDC, CMT0, CMT1 } },
+ { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
+ { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU1_AB, MTU1_VU, MTU2_AB,
+ MTU2_VU } },
+ { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU3_ABCD, MTU2_TCI3V, MTU4_ABCD,
+ MTU2_TCI4V } },
+ { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { ADC_ADI, IIC30, IIC31, IIC32 } },
+ { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { IIC33, SCIF0, SCIF1, SCIF2 } },
+ { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF3, SSU0, SSU1, SSI0_SSII } },
+#ifdef CONFIG_CPU_SUBTYPE_SH7203
+ { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
+ SSI3_SSII, 0 } },
+ { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, 0, RTC, RCAN0 } },
+ { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, 0, 0, 0 } },
+#else
+ { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
+ SSI3_SSII, ROMDEC } },
+ { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, SDHI, RTC, RCAN0 } },
+ { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, SRC, IEBI, 0 } },
+#endif
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfffe0808, 0, 16, /* PINTER */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7203", vectors, groups,
+ mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfffe8000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 193, 194, 195, 192 },
+ }, {
+ .mapbase = 0xfffe8800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 197, 198, 199, 196 },
+ }, {
+ .mapbase = 0xfffe9000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 201, 202, 203, 200 },
+ }, {
+ .mapbase = 0xfffe9800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 205, 206, 207, 204 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xffff2000,
+ .end = 0xffff2000 + 0x58 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = 232,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = 233,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = 231,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static struct platform_device *sh7203_devices[] __initdata = {
+ &sci_device,
+ &rtc_device,
+};
+
+static int __init sh7203_devices_setup(void)
+{
+ return platform_add_devices(sh7203_devices,
+ ARRAY_SIZE(sh7203_devices));
+}
+__initcall(sh7203_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index bd745aa87222..a564425b905f 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -167,7 +167,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups,
- NULL, mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers, NULL);
static struct plat_sci_port sci_platform_data[] = {
{
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 646eb6933614..3ae4d9111f19 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o
obj-$(CONFIG_CPU_SUBTYPE_SH7720) += setup-sh7720.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7721) += setup-sh7720.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
@@ -21,5 +22,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7710.o
clock-$(CONFIG_CPU_SUBTYPE_SH7720) := clock-sh7710.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7712) := clock-sh7712.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7712.c b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
new file mode 100644
index 000000000000..54f54df51ef0
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
@@ -0,0 +1,71 @@
+/*
+ * arch/sh/kernel/cpu/sh3/clock-sh7712.c
+ *
+ * SH7712 support for the clock framework
+ *
+ * Copyright (C) 2007 Andrew Murray <amurray@mpc-data.co.uk>
+ *
+ * Based on arch/sh/kernel/cpu/sh3/clock-sh3.c
+ * Copyright (C) 2005 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int multipliers[] = { 1, 2, 3 };
+static int divisors[] = { 1, 2, 3, 4, 6 };
+
+static void master_clk_init(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = (frqcr & 0x0300) >> 8;
+
+ clk->rate *= multipliers[idx];
+}
+
+static struct clk_ops sh7712_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = frqcr & 0x0007;
+
+ clk->rate = clk->parent->rate / divisors[idx];
+}
+
+static struct clk_ops sh7712_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = (frqcr & 0x0030) >> 4;
+
+ clk->rate = clk->parent->rate / divisors[idx];
+}
+
+static struct clk_ops sh7712_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7712_clk_ops[] = {
+ &sh7712_master_clk_ops,
+ &sh7712_module_clk_ops,
+ &sh7712_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7712_clk_ops))
+ *ops = sh7712_clk_ops[idx];
+}
+
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 0d12a124055c..4004073f98cd 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -13,8 +13,9 @@
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
-#include <asm/cpu/mmu_context.h>
#include <asm/unistd.h>
+#include <asm/cpu/mmu_context.h>
+#include <asm/page.h>
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -409,6 +410,27 @@ ENTRY(handle_exception)
! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
! save all registers onto stack.
!
+
+#ifdef CONFIG_GUSA
+ ! Check for roll back gRB (User and Kernel)
+ mov r15, k0
+ shll k0
+ bf/s 1f
+ shll k0
+ bf/s 1f
+ stc spc, k1
+ stc r0_bank, k0
+ cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
+ bt/s 2f
+ stc r1_bank, k1
+
+ add #-2, k0
+ add r15, k0
+ ldc k0, spc ! PC = saved r0 + r15 - 2
+2: mov k1, r15 ! SP = r1
+1:
+#endif
+
stc ssr, k0 ! Is it from kernel space?
shll k0 ! Check MD bit (bit30) by shifting it into...
shll k0 ! ...the T bit
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index b6abf38d3a8d..11b6d9c6edae 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -36,7 +36,7 @@ ENTRY(exception_handling_table)
.long exception_error ! address error store /* 100 */
#endif
#if defined(CONFIG_SH_FPU)
- .long do_fpu_error /* 120 */
+ .long fpu_error_trap_handler /* 120 */
#else
.long exception_error /* 120 */
#endif
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index bf579e061e09..fcc80bb7bee7 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -16,11 +16,11 @@
#include <asm/cache.h>
#include <asm/io.h>
-int __init detect_cpu_and_cache_system(void)
+int __uses_jump_to_uncached detect_cpu_and_cache_system(void)
{
unsigned long addr0, addr1, data0, data1, data2, data3;
- jump_to_P2();
+ jump_to_uncached();
/*
* Check if the entry shadows or not.
* When shadowed, it's 128-entry system.
@@ -48,7 +48,7 @@ int __init detect_cpu_and_cache_system(void)
ctrl_outl(data0&~SH_CACHE_VALID, addr0);
ctrl_outl(data2&~SH_CACHE_VALID, addr1);
- back_to_P1();
+ back_to_cached();
boot_cpu_data.dcache.ways = 4;
boot_cpu_data.dcache.entry_shift = 4;
@@ -84,6 +84,9 @@ int __init detect_cpu_and_cache_system(void)
#if defined(CONFIG_CPU_SUBTYPE_SH7720)
boot_cpu_data.type = CPU_SH7720;
#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7721)
+ boot_cpu_data.type = CPU_SH7721;
+#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
boot_cpu_data.type = CPU_SH7705;
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index f6c65f2659e9..dd0a20a685f7 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -66,12 +66,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(DMAC, 7),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(SCIF0, 3),
-};
-
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
@@ -85,7 +79,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct intc_vect vectors_irq[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
@@ -93,7 +87,7 @@ static struct intc_vect vectors_irq[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq, "sh7705-irq", vectors_irq, NULL,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct plat_sci_port sci_platform_data[] = {
{
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 60b04b1f9453..969804bb523b 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -81,13 +81,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(DMAC, 7),
- INTC_PRIO(SCI, 3),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(SCIF0, 3),
-};
-
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
@@ -109,7 +102,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
@@ -120,7 +113,7 @@ static struct intc_vect vectors_irq[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
#endif
static struct resource rtc_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 84e5629fa841..0cc0e2bf135d 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -73,18 +73,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(DMAC1, 7),
- INTC_PRIO(DMAC2, 7),
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
- INTC_PRIO(SIOF0, 3),
- INTC_PRIO(SIOF1, 3),
- INTC_PRIO(EDMAC0, 5),
- INTC_PRIO(EDMAC1, 5),
- INTC_PRIO(EDMAC2, 5),
-};
-
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
@@ -101,7 +89,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct intc_vect vectors_irq[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
@@ -109,7 +97,7 @@ static struct intc_vect vectors_irq[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq, "sh7710-irq", vectors_irq, NULL,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct resource rtc_resources[] = {
[0] = {
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index a0929b8a95ae..3855ea4c21c8 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -85,9 +85,62 @@ static struct platform_device sci_device = {
},
};
+static struct resource usb_ohci_resources[] = {
+ [0] = {
+ .start = 0xA4428000,
+ .end = 0xA44280FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 67,
+ .end = 67,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 usb_ohci_dma_mask = 0xffffffffUL;
+static struct platform_device usb_ohci_device = {
+ .name = "sh_ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &usb_ohci_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(usb_ohci_resources),
+ .resource = usb_ohci_resources,
+};
+
+static struct resource usbf_resources[] = {
+ [0] = {
+ .name = "sh_udc",
+ .start = 0xA4420000,
+ .end = 0xA44200FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "sh_udc",
+ .start = 65,
+ .end = 65,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usbf_device = {
+ .name = "sh_udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(usbf_resources),
+ .resource = usbf_resources,
+};
+
static struct platform_device *sh7720_devices[] __initdata = {
&rtc_device,
&sci_device,
+ &usb_ohci_device,
+ &usbf_device,
};
static int __init sh7720_devices_setup(void)
@@ -127,8 +180,11 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(USBF_SPD, 0x6e0), INTC_VECT(DMAC1_DEI0, 0x800),
INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840),
INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900),
- INTC_VECT(SSL, 0x980), INTC_VECT(USBFI0, 0xa20),
- INTC_VECT(USBFI1, 0xa40), INTC_VECT(USBHI, 0xa60),
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+ INTC_VECT(SSL, 0x980),
+#endif
+ INTC_VECT(USBFI0, 0xa20), INTC_VECT(USBFI1, 0xa40),
+ INTC_VECT(USBHI, 0xa60),
INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0),
INTC_VECT(ADC, 0xbe0), INTC_VECT(SCIF0, 0xc00),
INTC_VECT(SCIF1, 0xc20), INTC_VECT(PINT07, 0xc80),
@@ -153,22 +209,16 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 2),
- INTC_PRIO(SCIF1, 2),
- INTC_PRIO(DMAC1, 1),
- INTC_PRIO(DMAC2, 1),
- INTC_PRIO(RTC, 2),
- INTC_PRIO(TMU, 2),
- INTC_PRIO(TPU, 2),
-};
-
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
{ 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } },
+#if defined(CONFIG_CPU_SUBTYPE_SH7720)
{ 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } },
+#else
+ { 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, 0 } },
+#endif
{ 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } },
{ 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } },
{ 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } },
@@ -177,7 +227,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
static struct intc_sense_reg sense_registers[] __initdata = {
{ INTC_ICR1, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
@@ -190,7 +240,7 @@ static struct intc_vect vectors_irq[] __initdata = {
};
static DECLARE_INTC_DESC(intc_irq_desc, "sh7720-irq", vectors_irq,
- NULL, priorities, NULL, prio_registers, sense_registers);
+ NULL, NULL, prio_registers, sense_registers);
void __init plat_irq_setup_pins(int mode)
{
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index dadd6bffc128..d608557c7a3f 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -5,7 +5,7 @@
obj-y := probe.o common.o
common-y += $(addprefix ../sh3/, entry.o ex.o)
-obj-$(CONFIG_SH_FPU) += fpu.o
+obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# CPU subtype setup
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index c5a4fc77fa06..817f9939cda6 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -1,7 +1,4 @@
-/* $Id: fpu.c,v 1.4 2004/01/13 05:52:11 kkojima Exp $
- *
- * linux/arch/sh/kernel/fpu.c
- *
+/*
* Save/restore floating point context for signal handlers.
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -9,15 +6,16 @@
* for more details.
*
* Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
+ * Copyright (C) 2006 ST Microelectronics Ltd. (denorm support)
*
- * FIXME! These routines can be optimized in big endian case.
+ * FIXME! These routines have not been tested for big endian case.
*/
-
#include <linux/sched.h>
#include <linux/signal.h>
+#include <linux/io.h>
+#include <asm/cpu/fpu.h>
#include <asm/processor.h>
#include <asm/system.h>
-#include <asm/io.h>
/* The PR (precision) bit in the FP Status Register must be clear when
* an frchg instruction is executed, otherwise the instruction is undefined.
@@ -25,177 +23,184 @@
*/
#define FPSCR_RCHG 0x00000000
+extern unsigned long long float64_div(unsigned long long a,
+ unsigned long long b);
+extern unsigned long int float32_div(unsigned long int a, unsigned long int b);
+extern unsigned long long float64_mul(unsigned long long a,
+ unsigned long long b);
+extern unsigned long int float32_mul(unsigned long int a, unsigned long int b);
+extern unsigned long long float64_add(unsigned long long a,
+ unsigned long long b);
+extern unsigned long int float32_add(unsigned long int a, unsigned long int b);
+extern unsigned long long float64_sub(unsigned long long a,
+ unsigned long long b);
+extern unsigned long int float32_sub(unsigned long int a, unsigned long int b);
+static unsigned int fpu_exception_flags;
/*
* Save FPU registers onto task structure.
* Assume called with FPU enabled (SR.FD=0).
*/
-void
-save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
unsigned long dummy;
clear_tsk_thread_flag(tsk, TIF_USEDFPU);
enable_fpu();
- asm volatile("sts.l fpul, @-%0\n\t"
- "sts.l fpscr, @-%0\n\t"
- "lds %2, fpscr\n\t"
- "frchg\n\t"
- "fmov.s fr15, @-%0\n\t"
- "fmov.s fr14, @-%0\n\t"
- "fmov.s fr13, @-%0\n\t"
- "fmov.s fr12, @-%0\n\t"
- "fmov.s fr11, @-%0\n\t"
- "fmov.s fr10, @-%0\n\t"
- "fmov.s fr9, @-%0\n\t"
- "fmov.s fr8, @-%0\n\t"
- "fmov.s fr7, @-%0\n\t"
- "fmov.s fr6, @-%0\n\t"
- "fmov.s fr5, @-%0\n\t"
- "fmov.s fr4, @-%0\n\t"
- "fmov.s fr3, @-%0\n\t"
- "fmov.s fr2, @-%0\n\t"
- "fmov.s fr1, @-%0\n\t"
- "fmov.s fr0, @-%0\n\t"
- "frchg\n\t"
- "fmov.s fr15, @-%0\n\t"
- "fmov.s fr14, @-%0\n\t"
- "fmov.s fr13, @-%0\n\t"
- "fmov.s fr12, @-%0\n\t"
- "fmov.s fr11, @-%0\n\t"
- "fmov.s fr10, @-%0\n\t"
- "fmov.s fr9, @-%0\n\t"
- "fmov.s fr8, @-%0\n\t"
- "fmov.s fr7, @-%0\n\t"
- "fmov.s fr6, @-%0\n\t"
- "fmov.s fr5, @-%0\n\t"
- "fmov.s fr4, @-%0\n\t"
- "fmov.s fr3, @-%0\n\t"
- "fmov.s fr2, @-%0\n\t"
- "fmov.s fr1, @-%0\n\t"
- "fmov.s fr0, @-%0\n\t"
- "lds %3, fpscr\n\t"
- : "=r" (dummy)
- : "0" ((char *)(&tsk->thread.fpu.hard.status)),
- "r" (FPSCR_RCHG),
- "r" (FPSCR_INIT)
- : "memory");
-
- disable_fpu();
- release_fpu(regs);
+ asm volatile ("sts.l fpul, @-%0\n\t"
+ "sts.l fpscr, @-%0\n\t"
+ "lds %2, fpscr\n\t"
+ "frchg\n\t"
+ "fmov.s fr15, @-%0\n\t"
+ "fmov.s fr14, @-%0\n\t"
+ "fmov.s fr13, @-%0\n\t"
+ "fmov.s fr12, @-%0\n\t"
+ "fmov.s fr11, @-%0\n\t"
+ "fmov.s fr10, @-%0\n\t"
+ "fmov.s fr9, @-%0\n\t"
+ "fmov.s fr8, @-%0\n\t"
+ "fmov.s fr7, @-%0\n\t"
+ "fmov.s fr6, @-%0\n\t"
+ "fmov.s fr5, @-%0\n\t"
+ "fmov.s fr4, @-%0\n\t"
+ "fmov.s fr3, @-%0\n\t"
+ "fmov.s fr2, @-%0\n\t"
+ "fmov.s fr1, @-%0\n\t"
+ "fmov.s fr0, @-%0\n\t"
+ "frchg\n\t"
+ "fmov.s fr15, @-%0\n\t"
+ "fmov.s fr14, @-%0\n\t"
+ "fmov.s fr13, @-%0\n\t"
+ "fmov.s fr12, @-%0\n\t"
+ "fmov.s fr11, @-%0\n\t"
+ "fmov.s fr10, @-%0\n\t"
+ "fmov.s fr9, @-%0\n\t"
+ "fmov.s fr8, @-%0\n\t"
+ "fmov.s fr7, @-%0\n\t"
+ "fmov.s fr6, @-%0\n\t"
+ "fmov.s fr5, @-%0\n\t"
+ "fmov.s fr4, @-%0\n\t"
+ "fmov.s fr3, @-%0\n\t"
+ "fmov.s fr2, @-%0\n\t"
+ "fmov.s fr1, @-%0\n\t"
+ "fmov.s fr0, @-%0\n\t"
+ "lds %3, fpscr\n\t":"=r" (dummy)
+ :"0"((char *)(&tsk->thread.fpu.hard.status)),
+ "r"(FPSCR_RCHG), "r"(FPSCR_INIT)
+ :"memory");
+
+ disable_fpu();
+ release_fpu(regs);
}
-static void
-restore_fpu(struct task_struct *tsk)
+static void restore_fpu(struct task_struct *tsk)
{
unsigned long dummy;
- enable_fpu();
- asm volatile("lds %2, fpscr\n\t"
- "fmov.s @%0+, fr0\n\t"
- "fmov.s @%0+, fr1\n\t"
- "fmov.s @%0+, fr2\n\t"
- "fmov.s @%0+, fr3\n\t"
- "fmov.s @%0+, fr4\n\t"
- "fmov.s @%0+, fr5\n\t"
- "fmov.s @%0+, fr6\n\t"
- "fmov.s @%0+, fr7\n\t"
- "fmov.s @%0+, fr8\n\t"
- "fmov.s @%0+, fr9\n\t"
- "fmov.s @%0+, fr10\n\t"
- "fmov.s @%0+, fr11\n\t"
- "fmov.s @%0+, fr12\n\t"
- "fmov.s @%0+, fr13\n\t"
- "fmov.s @%0+, fr14\n\t"
- "fmov.s @%0+, fr15\n\t"
- "frchg\n\t"
- "fmov.s @%0+, fr0\n\t"
- "fmov.s @%0+, fr1\n\t"
- "fmov.s @%0+, fr2\n\t"
- "fmov.s @%0+, fr3\n\t"
- "fmov.s @%0+, fr4\n\t"
- "fmov.s @%0+, fr5\n\t"
- "fmov.s @%0+, fr6\n\t"
- "fmov.s @%0+, fr7\n\t"
- "fmov.s @%0+, fr8\n\t"
- "fmov.s @%0+, fr9\n\t"
- "fmov.s @%0+, fr10\n\t"
- "fmov.s @%0+, fr11\n\t"
- "fmov.s @%0+, fr12\n\t"
- "fmov.s @%0+, fr13\n\t"
- "fmov.s @%0+, fr14\n\t"
- "fmov.s @%0+, fr15\n\t"
- "frchg\n\t"
- "lds.l @%0+, fpscr\n\t"
- "lds.l @%0+, fpul\n\t"
- : "=r" (dummy)
- : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
- : "memory");
+ enable_fpu();
+ asm volatile ("lds %2, fpscr\n\t"
+ "fmov.s @%0+, fr0\n\t"
+ "fmov.s @%0+, fr1\n\t"
+ "fmov.s @%0+, fr2\n\t"
+ "fmov.s @%0+, fr3\n\t"
+ "fmov.s @%0+, fr4\n\t"
+ "fmov.s @%0+, fr5\n\t"
+ "fmov.s @%0+, fr6\n\t"
+ "fmov.s @%0+, fr7\n\t"
+ "fmov.s @%0+, fr8\n\t"
+ "fmov.s @%0+, fr9\n\t"
+ "fmov.s @%0+, fr10\n\t"
+ "fmov.s @%0+, fr11\n\t"
+ "fmov.s @%0+, fr12\n\t"
+ "fmov.s @%0+, fr13\n\t"
+ "fmov.s @%0+, fr14\n\t"
+ "fmov.s @%0+, fr15\n\t"
+ "frchg\n\t"
+ "fmov.s @%0+, fr0\n\t"
+ "fmov.s @%0+, fr1\n\t"
+ "fmov.s @%0+, fr2\n\t"
+ "fmov.s @%0+, fr3\n\t"
+ "fmov.s @%0+, fr4\n\t"
+ "fmov.s @%0+, fr5\n\t"
+ "fmov.s @%0+, fr6\n\t"
+ "fmov.s @%0+, fr7\n\t"
+ "fmov.s @%0+, fr8\n\t"
+ "fmov.s @%0+, fr9\n\t"
+ "fmov.s @%0+, fr10\n\t"
+ "fmov.s @%0+, fr11\n\t"
+ "fmov.s @%0+, fr12\n\t"
+ "fmov.s @%0+, fr13\n\t"
+ "fmov.s @%0+, fr14\n\t"
+ "fmov.s @%0+, fr15\n\t"
+ "frchg\n\t"
+ "lds.l @%0+, fpscr\n\t"
+ "lds.l @%0+, fpul\n\t"
+ :"=r" (dummy)
+ :"0"(&tsk->thread.fpu), "r"(FPSCR_RCHG)
+ :"memory");
disable_fpu();
}
/*
* Load the FPU with signalling NANS. This bit pattern we're using
* has the property that no matter wether considered as single or as
- * double precision represents signaling NANS.
+ * double precision represents signaling NANS.
*/
-static void
-fpu_init(void)
+static void fpu_init(void)
{
enable_fpu();
- asm volatile("lds %0, fpul\n\t"
- "lds %1, fpscr\n\t"
- "fsts fpul, fr0\n\t"
- "fsts fpul, fr1\n\t"
- "fsts fpul, fr2\n\t"
- "fsts fpul, fr3\n\t"
- "fsts fpul, fr4\n\t"
- "fsts fpul, fr5\n\t"
- "fsts fpul, fr6\n\t"
- "fsts fpul, fr7\n\t"
- "fsts fpul, fr8\n\t"
- "fsts fpul, fr9\n\t"
- "fsts fpul, fr10\n\t"
- "fsts fpul, fr11\n\t"
- "fsts fpul, fr12\n\t"
- "fsts fpul, fr13\n\t"
- "fsts fpul, fr14\n\t"
- "fsts fpul, fr15\n\t"
- "frchg\n\t"
- "fsts fpul, fr0\n\t"
- "fsts fpul, fr1\n\t"
- "fsts fpul, fr2\n\t"
- "fsts fpul, fr3\n\t"
- "fsts fpul, fr4\n\t"
- "fsts fpul, fr5\n\t"
- "fsts fpul, fr6\n\t"
- "fsts fpul, fr7\n\t"
- "fsts fpul, fr8\n\t"
- "fsts fpul, fr9\n\t"
- "fsts fpul, fr10\n\t"
- "fsts fpul, fr11\n\t"
- "fsts fpul, fr12\n\t"
- "fsts fpul, fr13\n\t"
- "fsts fpul, fr14\n\t"
- "fsts fpul, fr15\n\t"
- "frchg\n\t"
- "lds %2, fpscr\n\t"
- : /* no output */
- : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
- disable_fpu();
+ asm volatile ( "lds %0, fpul\n\t"
+ "lds %1, fpscr\n\t"
+ "fsts fpul, fr0\n\t"
+ "fsts fpul, fr1\n\t"
+ "fsts fpul, fr2\n\t"
+ "fsts fpul, fr3\n\t"
+ "fsts fpul, fr4\n\t"
+ "fsts fpul, fr5\n\t"
+ "fsts fpul, fr6\n\t"
+ "fsts fpul, fr7\n\t"
+ "fsts fpul, fr8\n\t"
+ "fsts fpul, fr9\n\t"
+ "fsts fpul, fr10\n\t"
+ "fsts fpul, fr11\n\t"
+ "fsts fpul, fr12\n\t"
+ "fsts fpul, fr13\n\t"
+ "fsts fpul, fr14\n\t"
+ "fsts fpul, fr15\n\t"
+ "frchg\n\t"
+ "fsts fpul, fr0\n\t"
+ "fsts fpul, fr1\n\t"
+ "fsts fpul, fr2\n\t"
+ "fsts fpul, fr3\n\t"
+ "fsts fpul, fr4\n\t"
+ "fsts fpul, fr5\n\t"
+ "fsts fpul, fr6\n\t"
+ "fsts fpul, fr7\n\t"
+ "fsts fpul, fr8\n\t"
+ "fsts fpul, fr9\n\t"
+ "fsts fpul, fr10\n\t"
+ "fsts fpul, fr11\n\t"
+ "fsts fpul, fr12\n\t"
+ "fsts fpul, fr13\n\t"
+ "fsts fpul, fr14\n\t"
+ "fsts fpul, fr15\n\t"
+ "frchg\n\t"
+ "lds %2, fpscr\n\t"
+ : /* no output */
+ :"r" (0), "r"(FPSCR_RCHG), "r"(FPSCR_INIT));
+ disable_fpu();
}
/**
- * denormal_to_double - Given denormalized float number,
- * store double float
+ * denormal_to_double - Given denormalized float number,
+ * store double float
*
- * @fpu: Pointer to sh_fpu_hard structure
- * @n: Index to FP register
+ * @fpu: Pointer to sh_fpu_hard structure
+ * @n: Index to FP register
*/
-static void
-denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
{
unsigned long du, dl;
unsigned long x = fpu->fpul;
@@ -212,7 +217,7 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
dl = x << 29;
fpu->fp_regs[n] = du;
- fpu->fp_regs[n+1] = dl;
+ fpu->fp_regs[n + 1] = dl;
}
}
@@ -223,68 +228,191 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
*
* Returns 1 when it's handled (should not cause exception).
*/
-static int
-ieee_fpe_handler (struct pt_regs *regs)
+static int ieee_fpe_handler(struct pt_regs *regs)
{
- unsigned short insn = *(unsigned short *) regs->pc;
+ unsigned short insn = *(unsigned short *)regs->pc;
unsigned short finsn;
unsigned long nextpc;
int nib[4] = {
(insn >> 12) & 0xf,
(insn >> 8) & 0xf,
(insn >> 4) & 0xf,
- insn & 0xf};
-
- if (nib[0] == 0xb ||
- (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
- regs->pr = regs->pc + 4;
-
- if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
- nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
- finsn = *(unsigned short *) (regs->pc + 2);
- } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
+ insn & 0xf
+ };
+
+ if (nib[0] == 0xb || (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb))
+ regs->pr = regs->pc + 4; /* bsr & jsr */
+
+ if (nib[0] == 0xa || nib[0] == 0xb) {
+ /* bra & bsr */
+ nextpc = regs->pc + 4 + ((short)((insn & 0xfff) << 4) >> 3);
+ finsn = *(unsigned short *)(regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xd) {
+ /* bt/s */
if (regs->sr & 1)
- nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+ nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
else
nextpc = regs->pc + 4;
- finsn = *(unsigned short *) (regs->pc + 2);
- } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
+ finsn = *(unsigned short *)(regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xf) {
+ /* bf/s */
if (regs->sr & 1)
nextpc = regs->pc + 4;
else
- nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
- finsn = *(unsigned short *) (regs->pc + 2);
+ nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
+ finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x4 && nib[3] == 0xb &&
- (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
+ (nib[2] == 0x0 || nib[2] == 0x2)) {
+ /* jmp & jsr */
nextpc = regs->regs[nib[1]];
- finsn = *(unsigned short *) (regs->pc + 2);
+ finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
- (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
+ (nib[2] == 0x0 || nib[2] == 0x2)) {
+ /* braf & bsrf */
nextpc = regs->pc + 4 + regs->regs[nib[1]];
- finsn = *(unsigned short *) (regs->pc + 2);
- } else if (insn == 0x000b) { /* rts */
+ finsn = *(unsigned short *)(regs->pc + 2);
+ } else if (insn == 0x000b) {
+ /* rts */
nextpc = regs->pr;
- finsn = *(unsigned short *) (regs->pc + 2);
+ finsn = *(unsigned short *)(regs->pc + 2);
} else {
nextpc = regs->pc + instruction_size(insn);
finsn = insn;
}
- if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
+ if ((finsn & 0xf1ff) == 0xf0ad) {
+ /* fcnvsd */
struct task_struct *tsk = current;
save_fpu(tsk, regs);
- if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
+ if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
/* FPU error */
- denormal_to_double (&tsk->thread.fpu.hard,
- (finsn >> 8) & 0xf);
- tsk->thread.fpu.hard.fpscr &=
- ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
- grab_fpu(regs);
- restore_fpu(tsk);
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ denormal_to_double(&tsk->thread.fpu.hard,
+ (finsn >> 8) & 0xf);
+ else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ } else if ((finsn & 0xf00f) == 0xf002) {
+ /* fmul */
+ struct task_struct *tsk = current;
+ int fpscr;
+ int n, m, prec;
+ unsigned int hx, hy;
+
+ n = (finsn >> 8) & 0xf;
+ m = (finsn >> 4) & 0xf;
+ hx = tsk->thread.fpu.hard.fp_regs[n];
+ hy = tsk->thread.fpu.hard.fp_regs[m];
+ fpscr = tsk->thread.fpu.hard.fpscr;
+ prec = fpscr & FPSCR_DBL_PRECISION;
+
+ if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (prec && ((hx & 0x7fffffff) < 0x00100000
+ || (hy & 0x7fffffff) < 0x00100000))) {
+ long long llx, lly;
+
+ /* FPU error because of denormal (doubles) */
+ llx = ((long long)hx << 32)
+ | tsk->thread.fpu.hard.fp_regs[n + 1];
+ lly = ((long long)hy << 32)
+ | tsk->thread.fpu.hard.fp_regs[m + 1];
+ llx = float64_mul(llx, lly);
+ tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
+ tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+ } else if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (!prec && ((hx & 0x7fffffff) < 0x00800000
+ || (hy & 0x7fffffff) < 0x00800000))) {
+ /* FPU error because of denormal (floats) */
+ hx = float32_mul(hx, hy);
+ tsk->thread.fpu.hard.fp_regs[n] = hx;
+ } else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ } else if ((finsn & 0xf00e) == 0xf000) {
+ /* fadd, fsub */
+ struct task_struct *tsk = current;
+ int fpscr;
+ int n, m, prec;
+ unsigned int hx, hy;
+
+ n = (finsn >> 8) & 0xf;
+ m = (finsn >> 4) & 0xf;
+ hx = tsk->thread.fpu.hard.fp_regs[n];
+ hy = tsk->thread.fpu.hard.fp_regs[m];
+ fpscr = tsk->thread.fpu.hard.fpscr;
+ prec = fpscr & FPSCR_DBL_PRECISION;
+
+ if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (prec && ((hx & 0x7fffffff) < 0x00100000
+ || (hy & 0x7fffffff) < 0x00100000))) {
+ long long llx, lly;
+
+ /* FPU error because of denormal (doubles) */
+ llx = ((long long)hx << 32)
+ | tsk->thread.fpu.hard.fp_regs[n + 1];
+ lly = ((long long)hy << 32)
+ | tsk->thread.fpu.hard.fp_regs[m + 1];
+ if ((finsn & 0xf00f) == 0xf000)
+ llx = float64_add(llx, lly);
+ else
+ llx = float64_sub(llx, lly);
+ tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
+ tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+ } else if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (!prec && ((hx & 0x7fffffff) < 0x00800000
+ || (hy & 0x7fffffff) < 0x00800000))) {
+ /* FPU error because of denormal (floats) */
+ if ((finsn & 0xf00f) == 0xf000)
+ hx = float32_add(hx, hy);
+ else
+ hx = float32_sub(hx, hy);
+ tsk->thread.fpu.hard.fp_regs[n] = hx;
+ } else
+ return 0;
+
+ regs->pc = nextpc;
+ return 1;
+ } else if ((finsn & 0xf003) == 0xf003) {
+ /* fdiv */
+ struct task_struct *tsk = current;
+ int fpscr;
+ int n, m, prec;
+ unsigned int hx, hy;
+
+ n = (finsn >> 8) & 0xf;
+ m = (finsn >> 4) & 0xf;
+ hx = tsk->thread.fpu.hard.fp_regs[n];
+ hy = tsk->thread.fpu.hard.fp_regs[m];
+ fpscr = tsk->thread.fpu.hard.fpscr;
+ prec = fpscr & FPSCR_DBL_PRECISION;
+
+ if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (prec && ((hx & 0x7fffffff) < 0x00100000
+ || (hy & 0x7fffffff) < 0x00100000))) {
+ long long llx, lly;
+
+ /* FPU error because of denormal (doubles) */
+ llx = ((long long)hx << 32)
+ | tsk->thread.fpu.hard.fp_regs[n + 1];
+ lly = ((long long)hy << 32)
+ | tsk->thread.fpu.hard.fp_regs[m + 1];
+
+ llx = float64_div(llx, lly);
+
+ tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
+ tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+ } else if ((fpscr & FPSCR_CAUSE_ERROR)
+ && (!prec && ((hx & 0x7fffffff) < 0x00800000
+ || (hy & 0x7fffffff) < 0x00800000))) {
+ /* FPU error because of denormal (floats) */
+ hx = float32_div(hx, hy);
+ tsk->thread.fpu.hard.fp_regs[n] = hx;
} else
- force_sig(SIGFPE, tsk);
+ return 0;
regs->pc = nextpc;
return 1;
@@ -293,27 +421,48 @@ ieee_fpe_handler (struct pt_regs *regs)
return 0;
}
-asmlinkage void
-do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7, struct pt_regs __regs)
+void float_raise(unsigned int flags)
+{
+ fpu_exception_flags |= flags;
+}
+
+int float_rounding_mode(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
struct task_struct *tsk = current;
+ int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.fpu.hard.fpscr);
+ return roundingMode;
+}
- if (ieee_fpe_handler(regs))
- return;
+BUILD_TRAP_HANDLER(fpu_error)
+{
+ struct task_struct *tsk = current;
+ TRAP_HANDLER_DECL;
- regs->pc += 2;
save_fpu(tsk, regs);
+ fpu_exception_flags = 0;
+ if (ieee_fpe_handler(regs)) {
+ tsk->thread.fpu.hard.fpscr &=
+ ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+ tsk->thread.fpu.hard.fpscr |= fpu_exception_flags;
+ /* Set the FPSCR flag as well as cause bits - simply
+ * replicate the cause */
+ tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
+ grab_fpu(regs);
+ restore_fpu(tsk);
+ set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
+ (fpu_exception_flags >> 2)) == 0) {
+ return;
+ }
+ }
+
force_sig(SIGFPE, tsk);
}
-asmlinkage void
-do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7, struct pt_regs __regs)
+BUILD_TRAP_HANDLER(fpu_state_restore)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
struct task_struct *tsk = current;
+ TRAP_HANDLER_DECL;
grab_fpu(regs);
if (!user_mode(regs)) {
@@ -324,7 +473,7 @@ do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
if (used_math()) {
/* Using the FPU again. */
restore_fpu(tsk);
- } else {
+ } else {
/* First time FPU user. */
fpu_init();
set_used_math();
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index bc9c28a69bf1..f2b9238cda04 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -98,6 +98,8 @@ int __init detect_cpu_and_cache_system(void)
case 0x200A:
if (prr == 0x61)
boot_cpu_data.type = CPU_SH7781;
+ else if (prr == 0xa1)
+ boot_cpu_data.type = CPU_SH7763;
else
boot_cpu_data.type = CPU_SH7780;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 523f68a9ce0e..ae3603aca615 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -126,12 +126,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(REF, REF_RCMI, REF_ROVI),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF, 3),
- INTC_PRIO(SCI1, 3),
- INTC_PRIO(DMAC, 7),
-};
-
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
@@ -143,7 +137,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
@@ -163,7 +157,7 @@ static struct intc_group groups_dma4[] __initdata = {
static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
vectors_dma4, groups_dma4,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
#endif
/* SH7750R and SH7751R both have 8-channel DMA controllers */
@@ -184,7 +178,7 @@ static struct intc_group groups_dma8[] __initdata = {
static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
vectors_dma8, groups_dma8,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
#endif
/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
@@ -205,7 +199,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
- vectors_tmu34, NULL, priorities,
+ vectors_tmu34, NULL,
mask_registers, prio_registers, NULL);
#endif
@@ -216,7 +210,7 @@ static struct intc_vect vectors_irlm[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
- priorities, NULL, prio_registers, NULL);
+ NULL, prio_registers, NULL);
/* SH7751 and SH7751R both have PCI */
#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
@@ -233,7 +227,7 @@ static struct intc_group groups_pci[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
- priorities, mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers, NULL);
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index 7a898cb1d940..85f81579b97e 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -92,15 +92,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(REF, REF_RCMI, REF_ROVI),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(SIM, 3),
- INTC_PRIO(DMAC, 7),
- INTC_PRIO(DMABRG, 13),
-};
-
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
{ IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21,
@@ -132,7 +123,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups,
- priorities, mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers, NULL);
static struct intc_vect vectors_irq[] __initdata = {
INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
@@ -140,7 +131,7 @@ static struct intc_vect vectors_irq[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups,
- priorities, mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers, NULL);
static struct plat_sci_port sci_platform_data[] = {
{
diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c
new file mode 100644
index 000000000000..7b2d337ee412
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/softfloat.c
@@ -0,0 +1,892 @@
+/*
+ * Floating point emulation support for subnormalised numbers on SH4
+ * architecture This file is derived from the SoftFloat IEC/IEEE
+ * Floating-point Arithmetic Package, Release 2 the original license of
+ * which is reproduced below.
+ *
+ * ========================================================================
+ *
+ * This C source file is part of the SoftFloat IEC/IEEE Floating-point
+ * Arithmetic Package, Release 2.
+ *
+ * Written by John R. Hauser. This work was made possible in part by the
+ * International Computer Science Institute, located at Suite 600, 1947 Center
+ * Street, Berkeley, California 94704. Funding was partially provided by the
+ * National Science Foundation under grant MIP-9311980. The original version
+ * of this code was written as part of a project to build a fixed-point vector
+ * processor in collaboration with the University of California at Berkeley,
+ * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+ * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+ * arithmetic/softfloat.html'.
+ *
+ * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+ * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+ * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+ * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+ * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+ *
+ * Derivative works are acceptable, even for commercial purposes, so long as
+ * (1) they include prominent notice that the work is derivative, and (2) they
+ * include prominent notice akin to these three paragraphs for those parts of
+ * this code that are retained.
+ *
+ * ========================================================================
+ *
+ * SH4 modifications by Ismail Dhaoui <ismail.dhaoui@st.com>
+ * and Kamel Khelifi <kamel.khelifi@st.com>
+ */
+#include <linux/kernel.h>
+#include <asm/cpu/fpu.h>
+
+#define LIT64( a ) a##LL
+
+typedef char flag;
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+
+typedef unsigned long int float32;
+typedef unsigned long long float64;
+
+extern void float_raise(unsigned int flags); /* in fpu.c */
+extern int float_rounding_mode(void); /* in fpu.c */
+
+inline bits64 extractFloat64Frac(float64 a);
+inline flag extractFloat64Sign(float64 a);
+inline int16 extractFloat64Exp(float64 a);
+inline int16 extractFloat32Exp(float32 a);
+inline flag extractFloat32Sign(float32 a);
+inline bits32 extractFloat32Frac(float32 a);
+inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig);
+inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr);
+inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig);
+inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr);
+float64 float64_sub(float64 a, float64 b);
+float32 float32_sub(float32 a, float32 b);
+float32 float32_add(float32 a, float32 b);
+float64 float64_add(float64 a, float64 b);
+float64 float64_div(float64 a, float64 b);
+float32 float32_div(float32 a, float32 b);
+float32 float32_mul(float32 a, float32 b);
+float64 float64_mul(float64 a, float64 b);
+inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+ bits64 * z1Ptr);
+inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+ bits64 * z1Ptr);
+inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr);
+
+static int8 countLeadingZeros32(bits32 a);
+static int8 countLeadingZeros64(bits64 a);
+static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp,
+ bits64 zSig);
+static float64 subFloat64Sigs(float64 a, float64 b, flag zSign);
+static float64 addFloat64Sigs(float64 a, float64 b, flag zSign);
+static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig);
+static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp,
+ bits32 zSig);
+static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig);
+static float32 subFloat32Sigs(float32 a, float32 b, flag zSign);
+static float32 addFloat32Sigs(float32 a, float32 b, flag zSign);
+static void normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr,
+ bits64 * zSigPtr);
+static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b);
+static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
+ bits32 * zSigPtr);
+
+inline bits64 extractFloat64Frac(float64 a)
+{
+ return a & LIT64(0x000FFFFFFFFFFFFF);
+}
+
+inline flag extractFloat64Sign(float64 a)
+{
+ return a >> 63;
+}
+
+inline int16 extractFloat64Exp(float64 a)
+{
+ return (a >> 52) & 0x7FF;
+}
+
+inline int16 extractFloat32Exp(float32 a)
+{
+ return (a >> 23) & 0xFF;
+}
+
+inline flag extractFloat32Sign(float32 a)
+{
+ return a >> 31;
+}
+
+inline bits32 extractFloat32Frac(float32 a)
+{
+ return a & 0x007FFFFF;
+}
+
+inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig)
+{
+ return (((bits64) zSign) << 63) + (((bits64) zExp) << 52) + zSig;
+}
+
+inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr)
+{
+ bits64 z;
+
+ if (count == 0) {
+ z = a;
+ } else if (count < 64) {
+ z = (a >> count) | ((a << ((-count) & 63)) != 0);
+ } else {
+ z = (a != 0);
+ }
+ *zPtr = z;
+}
+
+static int8 countLeadingZeros32(bits32 a)
+{
+ static const int8 countLeadingZerosHigh[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if (a < 0x10000) {
+ shiftCount += 16;
+ a <<= 16;
+ }
+ if (a < 0x1000000) {
+ shiftCount += 8;
+ a <<= 8;
+ }
+ shiftCount += countLeadingZerosHigh[a >> 24];
+ return shiftCount;
+
+}
+
+static int8 countLeadingZeros64(bits64 a)
+{
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if (a < ((bits64) 1) << 32) {
+ shiftCount += 32;
+ } else {
+ a >>= 32;
+ }
+ shiftCount += countLeadingZeros32(a);
+ return shiftCount;
+
+}
+
+static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64(zSig) - 1;
+ return roundAndPackFloat64(zSign, zExp - shiftCount,
+ zSig << shiftCount);
+
+}
+
+static float64 subFloat64Sigs(float64 a, float64 b, flag zSign)
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac(a);
+ aExp = extractFloat64Exp(a);
+ bSig = extractFloat64Frac(b);
+ bExp = extractFloat64Exp(b);
+ expDiff = aExp - bExp;
+ aSig <<= 10;
+ bSig <<= 10;
+ if (0 < expDiff)
+ goto aExpBigger;
+ if (expDiff < 0)
+ goto bExpBigger;
+ if (aExp == 0) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if (bSig < aSig)
+ goto aBigger;
+ if (aSig < bSig)
+ goto bBigger;
+ return packFloat64(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
+ bExpBigger:
+ if (bExp == 0x7FF) {
+ return packFloat64(zSign ^ 1, 0x7FF, 0);
+ }
+ if (aExp == 0) {
+ ++expDiff;
+ } else {
+ aSig |= LIT64(0x4000000000000000);
+ }
+ shift64RightJamming(aSig, -expDiff, &aSig);
+ bSig |= LIT64(0x4000000000000000);
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if (aExp == 0x7FF) {
+ return a;
+ }
+ if (bExp == 0) {
+ --expDiff;
+ } else {
+ bSig |= LIT64(0x4000000000000000);
+ }
+ shift64RightJamming(bSig, expDiff, &bSig);
+ aSig |= LIT64(0x4000000000000000);
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat64(zSign, zExp, zSig);
+
+}
+static float64 addFloat64Sigs(float64 a, float64 b, flag zSign)
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac(a);
+ aExp = extractFloat64Exp(a);
+ bSig = extractFloat64Frac(b);
+ bExp = extractFloat64Exp(b);
+ expDiff = aExp - bExp;
+ aSig <<= 9;
+ bSig <<= 9;
+ if (0 < expDiff) {
+ if (aExp == 0x7FF) {
+ return a;
+ }
+ if (bExp == 0) {
+ --expDiff;
+ } else {
+ bSig |= LIT64(0x2000000000000000);
+ }
+ shift64RightJamming(bSig, expDiff, &bSig);
+ zExp = aExp;
+ } else if (expDiff < 0) {
+ if (bExp == 0x7FF) {
+ return packFloat64(zSign, 0x7FF, 0);
+ }
+ if (aExp == 0) {
+ ++expDiff;
+ } else {
+ aSig |= LIT64(0x2000000000000000);
+ }
+ shift64RightJamming(aSig, -expDiff, &aSig);
+ zExp = bExp;
+ } else {
+ if (aExp == 0x7FF) {
+ return a;
+ }
+ if (aExp == 0)
+ return packFloat64(zSign, 0, (aSig + bSig) >> 9);
+ zSig = LIT64(0x4000000000000000) + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= LIT64(0x2000000000000000);
+ zSig = (aSig + bSig) << 1;
+ --zExp;
+ if ((sbits64) zSig < 0) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat64(zSign, zExp, zSig);
+
+}
+
+inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig)
+{
+ return (((bits32) zSign) << 31) + (((bits32) zExp) << 23) + zSig;
+}
+
+inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr)
+{
+ bits32 z;
+ if (count == 0) {
+ z = a;
+ } else if (count < 32) {
+ z = (a >> count) | ((a << ((-count) & 31)) != 0);
+ } else {
+ z = (a != 0);
+ }
+ *zPtr = z;
+}
+
+static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
+{
+ flag roundNearestEven;
+ int8 roundIncrement, roundBits;
+ flag isTiny;
+
+ /* SH4 has only 2 rounding modes - round to nearest and round to zero */
+ roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
+ roundIncrement = 0x40;
+ if (!roundNearestEven) {
+ roundIncrement = 0;
+ }
+ roundBits = zSig & 0x7F;
+ if (0xFD <= (bits16) zExp) {
+ if ((0xFD < zExp)
+ || ((zExp == 0xFD)
+ && ((sbits32) (zSig + roundIncrement) < 0))
+ ) {
+ float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
+ return packFloat32(zSign, 0xFF,
+ 0) - (roundIncrement == 0);
+ }
+ if (zExp < 0) {
+ isTiny = (zExp < -1)
+ || (zSig + roundIncrement < 0x80000000);
+ shift32RightJamming(zSig, -zExp, &zSig);
+ zExp = 0;
+ roundBits = zSig & 0x7F;
+ if (isTiny && roundBits)
+ float_raise(FPSCR_CAUSE_UNDERFLOW);
+ }
+ }
+ if (roundBits)
+ float_raise(FPSCR_CAUSE_INEXACT);
+ zSig = (zSig + roundIncrement) >> 7;
+ zSig &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
+ if (zSig == 0)
+ zExp = 0;
+ return packFloat32(zSign, zExp, zSig);
+
+}
+
+static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32(zSig) - 1;
+ return roundAndPackFloat32(zSign, zExp - shiftCount,
+ zSig << shiftCount);
+}
+
+static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
+{
+ flag roundNearestEven;
+ int16 roundIncrement, roundBits;
+ flag isTiny;
+
+ /* SH4 has only 2 rounding modes - round to nearest and round to zero */
+ roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
+ roundIncrement = 0x200;
+ if (!roundNearestEven) {
+ roundIncrement = 0;
+ }
+ roundBits = zSig & 0x3FF;
+ if (0x7FD <= (bits16) zExp) {
+ if ((0x7FD < zExp)
+ || ((zExp == 0x7FD)
+ && ((sbits64) (zSig + roundIncrement) < 0))
+ ) {
+ float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
+ return packFloat64(zSign, 0x7FF,
+ 0) - (roundIncrement == 0);
+ }
+ if (zExp < 0) {
+ isTiny = (zExp < -1)
+ || (zSig + roundIncrement <
+ LIT64(0x8000000000000000));
+ shift64RightJamming(zSig, -zExp, &zSig);
+ zExp = 0;
+ roundBits = zSig & 0x3FF;
+ if (isTiny && roundBits)
+ float_raise(FPSCR_CAUSE_UNDERFLOW);
+ }
+ }
+ if (roundBits)
+ float_raise(FPSCR_CAUSE_INEXACT);
+ zSig = (zSig + roundIncrement) >> 10;
+ zSig &= ~(((roundBits ^ 0x200) == 0) & roundNearestEven);
+ if (zSig == 0)
+ zExp = 0;
+ return packFloat64(zSign, zExp, zSig);
+
+}
+
+static float32 subFloat32Sigs(float32 a, float32 b, flag zSign)
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac(a);
+ aExp = extractFloat32Exp(a);
+ bSig = extractFloat32Frac(b);
+ bExp = extractFloat32Exp(b);
+ expDiff = aExp - bExp;
+ aSig <<= 7;
+ bSig <<= 7;
+ if (0 < expDiff)
+ goto aExpBigger;
+ if (expDiff < 0)
+ goto bExpBigger;
+ if (aExp == 0) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if (bSig < aSig)
+ goto aBigger;
+ if (aSig < bSig)
+ goto bBigger;
+ return packFloat32(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
+ bExpBigger:
+ if (bExp == 0xFF) {
+ return packFloat32(zSign ^ 1, 0xFF, 0);
+ }
+ if (aExp == 0) {
+ ++expDiff;
+ } else {
+ aSig |= 0x40000000;
+ }
+ shift32RightJamming(aSig, -expDiff, &aSig);
+ bSig |= 0x40000000;
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if (aExp == 0xFF) {
+ return a;
+ }
+ if (bExp == 0) {
+ --expDiff;
+ } else {
+ bSig |= 0x40000000;
+ }
+ shift32RightJamming(bSig, expDiff, &bSig);
+ aSig |= 0x40000000;
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat32(zSign, zExp, zSig);
+
+}
+
+static float32 addFloat32Sigs(float32 a, float32 b, flag zSign)
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac(a);
+ aExp = extractFloat32Exp(a);
+ bSig = extractFloat32Frac(b);
+ bExp = extractFloat32Exp(b);
+ expDiff = aExp - bExp;
+ aSig <<= 6;
+ bSig <<= 6;
+ if (0 < expDiff) {
+ if (aExp == 0xFF) {
+ return a;
+ }
+ if (bExp == 0) {
+ --expDiff;
+ } else {
+ bSig |= 0x20000000;
+ }
+ shift32RightJamming(bSig, expDiff, &bSig);
+ zExp = aExp;
+ } else if (expDiff < 0) {
+ if (bExp == 0xFF) {
+ return packFloat32(zSign, 0xFF, 0);
+ }
+ if (aExp == 0) {
+ ++expDiff;
+ } else {
+ aSig |= 0x20000000;
+ }
+ shift32RightJamming(aSig, -expDiff, &aSig);
+ zExp = bExp;
+ } else {
+ if (aExp == 0xFF) {
+ return a;
+ }
+ if (aExp == 0)
+ return packFloat32(zSign, 0, (aSig + bSig) >> 6);
+ zSig = 0x40000000 + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= 0x20000000;
+ zSig = (aSig + bSig) << 1;
+ --zExp;
+ if ((sbits32) zSig < 0) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat32(zSign, zExp, zSig);
+
+}
+
+float64 float64_sub(float64 a, float64 b)
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign(a);
+ bSign = extractFloat64Sign(b);
+ if (aSign == bSign) {
+ return subFloat64Sigs(a, b, aSign);
+ } else {
+ return addFloat64Sigs(a, b, aSign);
+ }
+
+}
+
+float32 float32_sub(float32 a, float32 b)
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign(a);
+ bSign = extractFloat32Sign(b);
+ if (aSign == bSign) {
+ return subFloat32Sigs(a, b, aSign);
+ } else {
+ return addFloat32Sigs(a, b, aSign);
+ }
+
+}
+
+float32 float32_add(float32 a, float32 b)
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign(a);
+ bSign = extractFloat32Sign(b);
+ if (aSign == bSign) {
+ return addFloat32Sigs(a, b, aSign);
+ } else {
+ return subFloat32Sigs(a, b, aSign);
+ }
+
+}
+
+float64 float64_add(float64 a, float64 b)
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign(a);
+ bSign = extractFloat64Sign(b);
+ if (aSign == bSign) {
+ return addFloat64Sigs(a, b, aSign);
+ } else {
+ return subFloat64Sigs(a, b, aSign);
+ }
+}
+
+static void
+normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr, bits64 * zSigPtr)
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64(aSig) - 11;
+ *zSigPtr = aSig << shiftCount;
+ *zExpPtr = 1 - shiftCount;
+}
+
+inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+ bits64 * z1Ptr)
+{
+ bits64 z1;
+
+ z1 = a1 + b1;
+ *z1Ptr = z1;
+ *z0Ptr = a0 + b0 + (z1 < a1);
+}
+
+inline void
+sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+ bits64 * z1Ptr)
+{
+ *z1Ptr = a1 - b1;
+ *z0Ptr = a0 - b0 - (a1 < b1);
+}
+
+static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b)
+{
+ bits64 b0, b1;
+ bits64 rem0, rem1, term0, term1;
+ bits64 z;
+ if (b <= a0)
+ return LIT64(0xFFFFFFFFFFFFFFFF);
+ b0 = b >> 32;
+ z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : (a0 / b0) << 32;
+ mul64To128(b, z, &term0, &term1);
+ sub128(a0, a1, term0, term1, &rem0, &rem1);
+ while (((sbits64) rem0) < 0) {
+ z -= LIT64(0x100000000);
+ b1 = b << 32;
+ add128(rem0, rem1, b0, b1, &rem0, &rem1);
+ }
+ rem0 = (rem0 << 32) | (rem1 >> 32);
+ z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : rem0 / b0;
+ return z;
+}
+
+inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr)
+{
+ bits32 aHigh, aLow, bHigh, bLow;
+ bits64 z0, zMiddleA, zMiddleB, z1;
+
+ aLow = a;
+ aHigh = a >> 32;
+ bLow = b;
+ bHigh = b >> 32;
+ z1 = ((bits64) aLow) * bLow;
+ zMiddleA = ((bits64) aLow) * bHigh;
+ zMiddleB = ((bits64) aHigh) * bLow;
+ z0 = ((bits64) aHigh) * bHigh;
+ zMiddleA += zMiddleB;
+ z0 += (((bits64) (zMiddleA < zMiddleB)) << 32) + (zMiddleA >> 32);
+ zMiddleA <<= 32;
+ z1 += zMiddleA;
+ z0 += (z1 < zMiddleA);
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
+ bits32 * zSigPtr)
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32(aSig) - 8;
+ *zSigPtr = aSig << shiftCount;
+ *zExpPtr = 1 - shiftCount;
+
+}
+
+float64 float64_div(float64 a, float64 b)
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ bits64 rem0, rem1;
+ bits64 term0, term1;
+
+ aSig = extractFloat64Frac(a);
+ aExp = extractFloat64Exp(a);
+ aSign = extractFloat64Sign(a);
+ bSig = extractFloat64Frac(b);
+ bExp = extractFloat64Exp(b);
+ bSign = extractFloat64Sign(b);
+ zSign = aSign ^ bSign;
+ if (aExp == 0x7FF) {
+ if (bExp == 0x7FF) {
+ }
+ return packFloat64(zSign, 0x7FF, 0);
+ }
+ if (bExp == 0x7FF) {
+ return packFloat64(zSign, 0, 0);
+ }
+ if (bExp == 0) {
+ if (bSig == 0) {
+ if ((aExp | aSig) == 0) {
+ float_raise(FPSCR_CAUSE_INVALID);
+ }
+ return packFloat64(zSign, 0x7FF, 0);
+ }
+ normalizeFloat64Subnormal(bSig, &bExp, &bSig);
+ }
+ if (aExp == 0) {
+ if (aSig == 0)
+ return packFloat64(zSign, 0, 0);
+ normalizeFloat64Subnormal(aSig, &aExp, &aSig);
+ }
+ zExp = aExp - bExp + 0x3FD;
+ aSig = (aSig | LIT64(0x0010000000000000)) << 10;
+ bSig = (bSig | LIT64(0x0010000000000000)) << 11;
+ if (bSig <= (aSig + aSig)) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = estimateDiv128To64(aSig, 0, bSig);
+ if ((zSig & 0x1FF) <= 2) {
+ mul64To128(bSig, zSig, &term0, &term1);
+ sub128(aSig, 0, term0, term1, &rem0, &rem1);
+ while ((sbits64) rem0 < 0) {
+ --zSig;
+ add128(rem0, rem1, 0, bSig, &rem0, &rem1);
+ }
+ zSig |= (rem1 != 0);
+ }
+ return roundAndPackFloat64(zSign, zExp, zSig);
+
+}
+
+float32 float32_div(float32 a, float32 b)
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+
+ aSig = extractFloat32Frac(a);
+ aExp = extractFloat32Exp(a);
+ aSign = extractFloat32Sign(a);
+ bSig = extractFloat32Frac(b);
+ bExp = extractFloat32Exp(b);
+ bSign = extractFloat32Sign(b);
+ zSign = aSign ^ bSign;
+ if (aExp == 0xFF) {
+ if (bExp == 0xFF) {
+ }
+ return packFloat32(zSign, 0xFF, 0);
+ }
+ if (bExp == 0xFF) {
+ return packFloat32(zSign, 0, 0);
+ }
+ if (bExp == 0) {
+ if (bSig == 0) {
+ return packFloat32(zSign, 0xFF, 0);
+ }
+ normalizeFloat32Subnormal(bSig, &bExp, &bSig);
+ }
+ if (aExp == 0) {
+ if (aSig == 0)
+ return packFloat32(zSign, 0, 0);
+ normalizeFloat32Subnormal(aSig, &aExp, &aSig);
+ }
+ zExp = aExp - bExp + 0x7D;
+ aSig = (aSig | 0x00800000) << 7;
+ bSig = (bSig | 0x00800000) << 8;
+ if (bSig <= (aSig + aSig)) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = (((bits64) aSig) << 32) / bSig;
+ if ((zSig & 0x3F) == 0) {
+ zSig |= (((bits64) bSig) * zSig != ((bits64) aSig) << 32);
+ }
+ return roundAndPackFloat32(zSign, zExp, zSig);
+
+}
+
+float32 float32_mul(float32 a, float32 b)
+{
+ char aSign, bSign, zSign;
+ int aExp, bExp, zExp;
+ unsigned int aSig, bSig;
+ unsigned long long zSig64;
+ unsigned int zSig;
+
+ aSig = extractFloat32Frac(a);
+ aExp = extractFloat32Exp(a);
+ aSign = extractFloat32Sign(a);
+ bSig = extractFloat32Frac(b);
+ bExp = extractFloat32Exp(b);
+ bSign = extractFloat32Sign(b);
+ zSign = aSign ^ bSign;
+ if (aExp == 0) {
+ if (aSig == 0)
+ return packFloat32(zSign, 0, 0);
+ normalizeFloat32Subnormal(aSig, &aExp, &aSig);
+ }
+ if (bExp == 0) {
+ if (bSig == 0)
+ return packFloat32(zSign, 0, 0);
+ normalizeFloat32Subnormal(bSig, &bExp, &bSig);
+ }
+ if ((bExp == 0xff && bSig == 0) || (aExp == 0xff && aSig == 0))
+ return roundAndPackFloat32(zSign, 0xff, 0);
+
+ zExp = aExp + bExp - 0x7F;
+ aSig = (aSig | 0x00800000) << 7;
+ bSig = (bSig | 0x00800000) << 8;
+ shift64RightJamming(((unsigned long long)aSig) * bSig, 32, &zSig64);
+ zSig = zSig64;
+ if (0 <= (signed int)(zSig << 1)) {
+ zSig <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat32(zSign, zExp, zSig);
+
+}
+
+float64 float64_mul(float64 a, float64 b)
+{
+ char aSign, bSign, zSign;
+ int aExp, bExp, zExp;
+ unsigned long long int aSig, bSig, zSig0, zSig1;
+
+ aSig = extractFloat64Frac(a);
+ aExp = extractFloat64Exp(a);
+ aSign = extractFloat64Sign(a);
+ bSig = extractFloat64Frac(b);
+ bExp = extractFloat64Exp(b);
+ bSign = extractFloat64Sign(b);
+ zSign = aSign ^ bSign;
+
+ if (aExp == 0) {
+ if (aSig == 0)
+ return packFloat64(zSign, 0, 0);
+ normalizeFloat64Subnormal(aSig, &aExp, &aSig);
+ }
+ if (bExp == 0) {
+ if (bSig == 0)
+ return packFloat64(zSign, 0, 0);
+ normalizeFloat64Subnormal(bSig, &bExp, &bSig);
+ }
+ if ((aExp == 0x7ff && aSig == 0) || (bExp == 0x7ff && bSig == 0))
+ return roundAndPackFloat64(zSign, 0x7ff, 0);
+
+ zExp = aExp + bExp - 0x3FF;
+ aSig = (aSig | 0x0010000000000000LL) << 10;
+ bSig = (bSig | 0x0010000000000000LL) << 11;
+ mul64To128(aSig, bSig, &zSig0, &zSig1);
+ zSig0 |= (zSig1 != 0);
+ if (0 <= (signed long long int)(zSig0 << 1)) {
+ zSig0 <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat64(zSign, zExp, zSig0);
+}
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 24539873943a..08ac6387bf17 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -3,6 +3,7 @@
#
# CPU subtype setup
+obj-$(CONFIG_CPU_SUBTYPE_SH7763) += setup-sh7763.o
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
@@ -14,6 +15,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
smp-$(CONFIG_CPU_SUBTYPE_SHX3) := smp-shx3.o
# Primary on-chip clocks (common)
+clock-$(CONFIG_CPU_SUBTYPE_SH7763) := clock-sh7763.o
clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
new file mode 100644
index 000000000000..45889d412c80
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
@@ -0,0 +1,126 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7763.c
+ *
+ * SH7763 support for the clock framework
+ *
+ * Copyright (C) 2005 Paul Mundt
+ * Copyright (C) 2007 Yoshihiro Shimoda
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int bfc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
+static int p0fc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
+static int p1fc_divisors[] = { 1, 1, 1, 16, 1, 1, 1, 1 };
+static int cfc_divisors[] = { 1, 1, 4, 1, 1, 1, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= p0fc_divisors[(ctrl_inl(FRQCR) >> 4) & 0x07];
+}
+
+static struct clk_ops sh7763_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> 4) & 0x07);
+ clk->rate = clk->parent->rate / p0fc_divisors[idx];
+}
+
+static struct clk_ops sh7763_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> 16) & 0x07);
+ clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops sh7763_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ clk->rate = clk->parent->rate;
+}
+
+static struct clk_ops sh7763_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7763_clk_ops[] = {
+ &sh7763_master_clk_ops,
+ &sh7763_module_clk_ops,
+ &sh7763_bus_clk_ops,
+ &sh7763_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7763_clk_ops))
+ *ops = sh7763_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> 20) & 0x07);
+ clk->rate = clk->parent->rate / cfc_divisors[idx];
+}
+
+static struct clk_ops sh7763_shyway_clk_ops = {
+ .recalc = shyway_clk_recalc,
+};
+
+static struct clk sh7763_shyway_clk = {
+ .name = "shyway_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7763_shyway_clk_ops,
+};
+
+/*
+ * Additional SH7763-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *sh7763_onchip_clocks[] = {
+ &sh7763_shyway_clk,
+};
+
+static int __init sh7763_clk_init(void)
+{
+ struct clk *clk = clk_get(NULL, "master_clk");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sh7763_onchip_clocks); i++) {
+ struct clk *clkp = sh7763_onchip_clocks[i];
+
+ clkp->parent = clk;
+ clk_register(clkp);
+ clk_enable(clkp);
+ }
+
+ /*
+ * Now that we have the rest of the clocks registered, we need to
+ * force the parent clock to propagate so that these clocks will
+ * automatically figure out their rate. We cheat by handing the
+ * parent clock its current rate and forcing child propagation.
+ */
+ clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_put(clk);
+
+ return 0;
+}
+
+arch_initcall(sh7763_clk_init);
+
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index b9c6547c4a90..73c778d40d13 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -157,14 +157,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(TMU0, 2),
- INTC_PRIO(TMU1, 2),
-};
-
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
{ } },
@@ -217,7 +209,7 @@ static struct intc_sense_reg sense_registers[] __initdata = {
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
+static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups,
mask_registers, prio_registers, sense_registers);
void __init plat_irq_setup(void)
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
new file mode 100644
index 000000000000..eabd5386812d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -0,0 +1,390 @@
+/*
+ * SH7763 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Yoshihiro Shimoda
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <asm/sci.h>
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xffe80000,
+ .end = 0xffe80000 + 0x58 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffe08000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 76, 77, 79, 78 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct resource usb_ohci_resources[] = {
+ [0] = {
+ .start = 0xffec8000,
+ .end = 0xffec80ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 83,
+ .end = 83,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 usb_ohci_dma_mask = 0xffffffffUL;
+static struct platform_device usb_ohci_device = {
+ .name = "sh_ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &usb_ohci_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(usb_ohci_resources),
+ .resource = usb_ohci_resources,
+};
+
+static struct resource usbf_resources[] = {
+ [0] = {
+ .start = 0xffec0000,
+ .end = 0xffec00ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 84,
+ .end = 84,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usbf_device = {
+ .name = "sh_udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(usbf_resources),
+ .resource = usbf_resources,
+};
+
+static struct platform_device *sh7763_devices[] __initdata = {
+ &rtc_device,
+ &sci_device,
+ &usb_ohci_device,
+ &usbf_device,
+};
+
+static int __init sh7763_devices_setup(void)
+{
+ return platform_add_devices(sh7763_devices,
+ ARRAY_SIZE(sh7763_devices));
+}
+__initcall(sh7763_devices_setup);
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL,
+
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
+ HUDI, LCDC,
+ DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ DMAC0_DMINT4, DMAC0_DMINT5,
+ IIC0, IIC1,
+ CMT,
+ GEINT0, GEINT1, GEINT2,
+ HAC,
+ PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+ PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+ STIF0, STIF1,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SIOF0, SIOF1, SIOF2,
+ USBH, USBFI0, USBFI1,
+ TPU, PCC,
+ MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+ SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
+ TMU3, TMU4, TMU5, ADC, SSI0, SSI1, SSI2, SSI3,
+ SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
+ GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3,
+
+ /* interrupt groups */
+
+ TMU012, TMU345, RTC, DMAC, SCIF0, GETHER, PCIC5,
+ SCIF1, USBF, MMCIF, SIM, SCIF2, GPIO,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(WDT, 0x560), INTC_VECT(TMU0, 0x580),
+ INTC_VECT(TMU1, 0x5a0), INTC_VECT(TMU2, 0x5c0),
+ INTC_VECT(TMU2_TICPI, 0x5e0), INTC_VECT(HUDI, 0x600),
+ INTC_VECT(LCDC, 0x620),
+ INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+ INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
+ INTC_VECT(DMAC0_DMAE, 0x6c0),
+ INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+ INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+ INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+ INTC_VECT(IIC0, 0x8A0), INTC_VECT(IIC1, 0x8C0),
+ INTC_VECT(CMT, 0x900), INTC_VECT(GEINT0, 0x920),
+ INTC_VECT(GEINT1, 0x940), INTC_VECT(GEINT2, 0x960),
+ INTC_VECT(HAC, 0x980),
+ INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+ INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+ INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+ INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+ INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+ INTC_VECT(STIF0, 0xb40), INTC_VECT(STIF1, 0xb60),
+ INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
+ INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+ INTC_VECT(SIOF0, 0xc00), INTC_VECT(SIOF1, 0xc20),
+ INTC_VECT(USBH, 0xc60), INTC_VECT(USBFI0, 0xc80),
+ INTC_VECT(USBFI1, 0xca0),
+ INTC_VECT(TPU, 0xcc0), INTC_VECT(PCC, 0xce0),
+ INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+ INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+ INTC_VECT(SIM_ERI, 0xd80), INTC_VECT(SIM_RXI, 0xda0),
+ INTC_VECT(SIM_TXI, 0xdc0), INTC_VECT(SIM_TEND, 0xde0),
+ INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+ INTC_VECT(TMU5, 0xe40), INTC_VECT(ADC, 0xe60),
+ INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
+ INTC_VECT(SSI2, 0xec0), INTC_VECT(SSI3, 0xee0),
+ INTC_VECT(SCIF1_ERI, 0xf00), INTC_VECT(SCIF1_RXI, 0xf20),
+ INTC_VECT(SCIF1_BRI, 0xf40), INTC_VECT(SCIF1_TXI, 0xf60),
+ INTC_VECT(GPIO_CH0, 0xf80), INTC_VECT(GPIO_CH1, 0xfa0),
+ INTC_VECT(GPIO_CH2, 0xfc0), INTC_VECT(GPIO_CH3, 0xfe0),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+ INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(DMAC, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+ DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(GETHER, GEINT0, GEINT1, GEINT2),
+ INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(USBF, USBFI0, USBFI1),
+ INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+ INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
+ INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+ INTC_GROUP(GPIO, GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3),
+};
+
+static struct intc_prio priorities[] __initdata = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SCIF2, 3),
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+ { 0, 0, 0, 0, 0, 0, GPIO, 0,
+ SSI0, MMCIF, 0, SIOF0, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+ PCIINTA, PCISERR, HAC, CMT, 0, 0, 0, DMAC,
+ HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
+ { 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
+ { 0, 0, 0, 0, 0, 0, SCIF2, USBF,
+ 0, 0, STIF1, STIF0, 0, 0, USBH, GETHER,
+ PCC, 0, 0, ADC, TPU, SIM, SIOF2, SIOF1,
+ LCDC, 0, IIC1, IIC0, SSI3, SSI2, SSI1, 0 } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
+ TMU2, TMU2_TICPI } },
+ { 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+ { 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+ { 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { HUDI, DMAC, ADC } },
+ { 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { CMT, HAC,
+ PCISERR, PCIINTA } },
+ { 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+ PCIINTD, PCIC5 } },
+ { 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { SIOF0, USBF, MMCIF, SSI0 } },
+ { 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { SCIF2, GPIO } },
+ { 0xffd400a0, 0, 32, 8, /* INT2PRI8 */ { SSI3, SSI2, SSI1, 0 } },
+ { 0xffd400a4, 0, 32, 8, /* INT2PRI9 */ { LCDC, 0, IIC1, IIC0 } },
+ { 0xffd400a8, 0, 32, 8, /* INT2PRI10 */ { TPU, SIM, SIOF2, SIOF1 } },
+ { 0xffd400ac, 0, 32, 8, /* INT2PRI11 */ { PCC } },
+ { 0xffd400b0, 0, 32, 8, /* INT2PRI12 */ { 0, 0, USBH, GETHER } },
+ { 0xffd400b4, 0, 32, 8, /* INT2PRI13 */ { 0, 0, STIF1, STIF0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7763", vectors, groups, priorities,
+ mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq_vectors[] __initdata = {
+ INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+ INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+ INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+ INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_mask_reg irq_mask_registers[] __initdata = {
+ { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] __initdata = {
+ { 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg irq_sense_registers[] __initdata = {
+ { 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7763-irq", irq_vectors,
+ NULL, NULL, irq_mask_registers, irq_prio_registers,
+ irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect irl_vectors[] __initdata = {
+ INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+ INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+ INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+ INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+ INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+ INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+ INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+ INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] __initdata = {
+ { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+ { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
+ { 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7763-irl7654", irl_vectors,
+ NULL, NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7763-irl3210", irl_vectors,
+ NULL, NULL, irl3210_mask_registers, NULL, NULL);
+
+#define INTC_ICR0 0xffd00000
+#define INTC_INTMSK0 0xffd00044
+#define INTC_INTMSK1 0xffd00048
+#define INTC_INTMSK2 0xffd40080
+#define INTC_INTMSKCLR1 0xffd00068
+#define INTC_INTMSKCLR2 0xffd40084
+
+void __init plat_irq_setup(void)
+{
+ /* disable IRQ7-0 */
+ ctrl_outl(0xff000000, INTC_INTMSK0);
+
+ /* disable IRL3-0 + IRL7-4 */
+ ctrl_outl(0xc0000000, INTC_INTMSK1);
+ ctrl_outl(0xfffefffe, INTC_INTMSK2);
+
+ register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ:
+ /* select IRQ mode for IRL3-0 + IRL7-4 */
+ ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0);
+ register_intc_controller(&intc_irq_desc);
+ break;
+ case IRQ_MODE_IRL7654:
+ /* enable IRL7-4 but don't provide any masking */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
+ break;
+ case IRQ_MODE_IRL3210:
+ /* enable IRL0-3 but don't provide any masking */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+ break;
+ case IRQ_MODE_IRL7654_MASK:
+ /* enable IRL7-4 and mask using cpu intc controller */
+ ctrl_outl(0x40000000, INTC_INTMSKCLR1);
+ register_intc_controller(&intc_irl7654_desc);
+ break;
+ case IRQ_MODE_IRL3210_MASK:
+ /* enable IRL0-3 and mask using cpu intc controller */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ register_intc_controller(&intc_irl3210_desc);
+ break;
+ default:
+ BUG();
+ }
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index e8fd33ff0605..293004b526ff 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -168,11 +168,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
-};
-
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
{ 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
@@ -195,7 +190,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
};
-static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
+static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups,
mask_registers, prio_registers, NULL);
/* Support for external interrupt pins in IRQ mode */
@@ -223,7 +218,7 @@ static struct intc_sense_reg irq_sense_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
- NULL, NULL, irq_mask_registers, irq_prio_registers,
+ NULL, irq_mask_registers, irq_prio_registers,
irq_sense_registers);
/* External interrupt pins in IRL mode */
@@ -257,10 +252,10 @@ static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
- NULL, NULL, irl7654_mask_registers, NULL, NULL);
+ NULL, irl7654_mask_registers, NULL, NULL);
static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
- NULL, NULL, irl3210_mask_registers, NULL, NULL);
+ NULL, irl3210_mask_registers, NULL, NULL);
#define INTC_ICR0 0xffd00000
#define INTC_INTMSK0 0xffd00044
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index 39b215d6cee5..74b60e96cdf4 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -178,15 +178,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(SCIF3, 3),
- INTC_PRIO(SCIF4, 3),
- INTC_PRIO(SCIF5, 3),
-};
-
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
@@ -227,7 +218,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd40024, 0, 32, 8, /* INT2PRI9 */ { DU, GDTA, } },
};
-static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups, priorities,
+static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups,
mask_registers, prio_registers, NULL);
/* Support for external interrupt pins in IRQ mode */
@@ -248,11 +239,11 @@ static struct intc_sense_reg sense_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq0123, "sh7785-irq0123", vectors_irq0123,
- NULL, NULL, mask_registers, prio_registers,
+ NULL, mask_registers, prio_registers,
sense_registers);
static DECLARE_INTC_DESC(intc_desc_irq4567, "sh7785-irq4567", vectors_irq4567,
- NULL, NULL, mask_registers, prio_registers,
+ NULL, mask_registers, prio_registers,
sense_registers);
/* External interrupt pins in IRL mode */
@@ -280,10 +271,10 @@ static struct intc_vect vectors_irl4567[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7785-irl0123", vectors_irl0123,
- NULL, NULL, mask_registers, NULL, NULL);
+ NULL, mask_registers, NULL, NULL);
static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567,
- NULL, NULL, mask_registers, NULL, NULL);
+ NULL, mask_registers, NULL, NULL);
#define INTC_ICR0 0xffd00000
#define INTC_INTMSK0 0xffd00044
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index c6cdd7e3b049..4dc958b6b314 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -165,13 +165,6 @@ static struct intc_group groups[] __initdata = {
INTC_GROUP(DTU3, DTU3_TEND, DTU3_AE, DTU3_TMISS),
};
-static struct intc_prio priorities[] __initdata = {
- INTC_PRIO(SCIF0, 3),
- INTC_PRIO(SCIF1, 3),
- INTC_PRIO(SCIF2, 3),
- INTC_PRIO(SCIF3, 3),
-};
-
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
{ IRQ0, IRQ1, IRQ2, IRQ3 } },
@@ -218,7 +211,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 4) },
};
-static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups, priorities,
+static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups,
mask_registers, prio_registers, NULL);
/* Support for external interrupt pins in IRQ mode */
@@ -232,8 +225,7 @@ static struct intc_sense_reg sense_registers[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
- priorities, mask_registers, prio_registers,
- sense_registers);
+ mask_registers, prio_registers, sense_registers);
/* External interrupt pins in IRL mode */
static struct intc_vect vectors_irl[] __initdata = {
@@ -248,7 +240,7 @@ static struct intc_vect vectors_irl[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
- priorities, mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers, NULL);
void __init plat_irq_setup_pins(int mode)
{
diff --git a/arch/sh/kernel/cpu/sh5/Makefile b/arch/sh/kernel/cpu/sh5/Makefile
new file mode 100644
index 000000000000..8646363e9ded
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux/SuperH SH-5 backends.
+#
+obj-y := entry.o probe.o switchto.o
+
+obj-$(CONFIG_SH_FPU) += fpu.o
+obj-$(CONFIG_KALLSYMS) += unwind.o
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
new file mode 100644
index 000000000000..ba8750176d91
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -0,0 +1,2101 @@
+/*
+ * arch/sh/kernel/cpu/sh5/entry.S
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2004 - 2007 Paul Mundt
+ * Copyright (C) 2003, 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/sys.h>
+#include <asm/cpu/registers.h>
+#include <asm/processor.h>
+#include <asm/unistd.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * SR fields.
+ */
+#define SR_ASID_MASK 0x00ff0000
+#define SR_FD_MASK 0x00008000
+#define SR_SS 0x08000000
+#define SR_BL 0x10000000
+#define SR_MD 0x40000000
+
+/*
+ * Event code.
+ */
+#define EVENT_INTERRUPT 0
+#define EVENT_FAULT_TLB 1
+#define EVENT_FAULT_NOT_TLB 2
+#define EVENT_DEBUG 3
+
+/* EXPEVT values */
+#define RESET_CAUSE 0x20
+#define DEBUGSS_CAUSE 0x980
+
+/*
+ * Frame layout. Quad index.
+ */
+#define FRAME_T(x) FRAME_TBASE+(x*8)
+#define FRAME_R(x) FRAME_RBASE+(x*8)
+#define FRAME_S(x) FRAME_SBASE+(x*8)
+#define FSPC 0
+#define FSSR 1
+#define FSYSCALL_ID 2
+
+/* Arrange the save frame to be a multiple of 32 bytes long */
+#define FRAME_SBASE 0
+#define FRAME_RBASE (FRAME_SBASE+(3*8)) /* SYSCALL_ID - SSR - SPC */
+#define FRAME_TBASE (FRAME_RBASE+(63*8)) /* r0 - r62 */
+#define FRAME_PBASE (FRAME_TBASE+(8*8)) /* tr0 -tr7 */
+#define FRAME_SIZE (FRAME_PBASE+(2*8)) /* pad0-pad1 */
+
+#define FP_FRAME_SIZE FP_FRAME_BASE+(33*8) /* dr0 - dr31 + fpscr */
+#define FP_FRAME_BASE 0
+
+#define SAVED_R2 0*8
+#define SAVED_R3 1*8
+#define SAVED_R4 2*8
+#define SAVED_R5 3*8
+#define SAVED_R18 4*8
+#define SAVED_R6 5*8
+#define SAVED_TR0 6*8
+
+/* These are the registers saved in the TLB path that aren't saved in the first
+ level of the normal one. */
+#define TLB_SAVED_R25 7*8
+#define TLB_SAVED_TR1 8*8
+#define TLB_SAVED_TR2 9*8
+#define TLB_SAVED_TR3 10*8
+#define TLB_SAVED_TR4 11*8
+/* Save R0/R1 : PT-migrating compiler currently dishounours -ffixed-r0 and -ffixed-r1 causing
+ breakage otherwise. */
+#define TLB_SAVED_R0 12*8
+#define TLB_SAVED_R1 13*8
+
+#define CLI() \
+ getcon SR, r6; \
+ ori r6, 0xf0, r6; \
+ putcon r6, SR;
+
+#define STI() \
+ getcon SR, r6; \
+ andi r6, ~0xf0, r6; \
+ putcon r6, SR;
+
+#ifdef CONFIG_PREEMPT
+# define preempt_stop() CLI()
+#else
+# define preempt_stop()
+# define resume_kernel restore_all
+#endif
+
+ .section .data, "aw"
+
+#define FAST_TLBMISS_STACK_CACHELINES 4
+#define FAST_TLBMISS_STACK_QUADWORDS (4*FAST_TLBMISS_STACK_CACHELINES)
+
+/* Register back-up area for all exceptions */
+ .balign 32
+ /* Allow for 16 quadwords to be pushed by fast tlbmiss handling
+ * register saves etc. */
+ .fill FAST_TLBMISS_STACK_QUADWORDS, 8, 0x0
+/* This is 32 byte aligned by construction */
+/* Register back-up area for all exceptions */
+reg_save_area:
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+ .quad 0
+ .quad 0
+
+/* Save area for RESVEC exceptions. We cannot use reg_save_area because of
+ * reentrancy. Note this area may be accessed via physical address.
+ * Align so this fits a whole single cache line, for ease of purging.
+ */
+ .balign 32,0,32
+resvec_save_area:
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .balign 32,0,32
+
+/* Jump table of 3rd level handlers */
+trap_jtable:
+ .long do_exception_error /* 0x000 */
+ .long do_exception_error /* 0x020 */
+ .long tlb_miss_load /* 0x040 */
+ .long tlb_miss_store /* 0x060 */
+ ! ARTIFICIAL pseudo-EXPEVT setting
+ .long do_debug_interrupt /* 0x080 */
+ .long tlb_miss_load /* 0x0A0 */
+ .long tlb_miss_store /* 0x0C0 */
+ .long do_address_error_load /* 0x0E0 */
+ .long do_address_error_store /* 0x100 */
+#ifdef CONFIG_SH_FPU
+ .long do_fpu_error /* 0x120 */
+#else
+ .long do_exception_error /* 0x120 */
+#endif
+ .long do_exception_error /* 0x140 */
+ .long system_call /* 0x160 */
+ .long do_reserved_inst /* 0x180 */
+ .long do_illegal_slot_inst /* 0x1A0 */
+ .long do_exception_error /* 0x1C0 - NMI */
+ .long do_exception_error /* 0x1E0 */
+ .rept 15
+ .long do_IRQ /* 0x200 - 0x3C0 */
+ .endr
+ .long do_exception_error /* 0x3E0 */
+ .rept 32
+ .long do_IRQ /* 0x400 - 0x7E0 */
+ .endr
+ .long fpu_error_or_IRQA /* 0x800 */
+ .long fpu_error_or_IRQB /* 0x820 */
+ .long do_IRQ /* 0x840 */
+ .long do_IRQ /* 0x860 */
+ .rept 6
+ .long do_exception_error /* 0x880 - 0x920 */
+ .endr
+ .long do_software_break_point /* 0x940 */
+ .long do_exception_error /* 0x960 */
+ .long do_single_step /* 0x980 */
+
+ .rept 3
+ .long do_exception_error /* 0x9A0 - 0x9E0 */
+ .endr
+ .long do_IRQ /* 0xA00 */
+ .long do_IRQ /* 0xA20 */
+ .long itlb_miss_or_IRQ /* 0xA40 */
+ .long do_IRQ /* 0xA60 */
+ .long do_IRQ /* 0xA80 */
+ .long itlb_miss_or_IRQ /* 0xAA0 */
+ .long do_exception_error /* 0xAC0 */
+ .long do_address_error_exec /* 0xAE0 */
+ .rept 8
+ .long do_exception_error /* 0xB00 - 0xBE0 */
+ .endr
+ .rept 18
+ .long do_IRQ /* 0xC00 - 0xE20 */
+ .endr
+
+ .section .text64, "ax"
+
+/*
+ * --- Exception/Interrupt/Event Handling Section
+ */
+
+/*
+ * VBR and RESVEC blocks.
+ *
+ * First level handler for VBR-based exceptions.
+ *
+ * To avoid waste of space, align to the maximum text block size.
+ * This is assumed to be at most 128 bytes or 32 instructions.
+ * DO NOT EXCEED 32 instructions on the first level handlers !
+ *
+ * Also note that RESVEC is contained within the VBR block
+ * where the room left (1KB - TEXT_SIZE) allows placing
+ * the RESVEC block (at most 512B + TEXT_SIZE).
+ *
+ * So first (and only) level handler for RESVEC-based exceptions.
+ *
+ * Where the fault/interrupt is handled (not_a_tlb_miss, tlb_miss
+ * and interrupt) we are a lot tight with register space until
+ * saving onto the stack frame, which is done in handle_exception().
+ *
+ */
+
+#define TEXT_SIZE 128
+#define BLOCK_SIZE 1664 /* Dynamic check, 13*128 */
+
+ .balign TEXT_SIZE
+LVBR_block:
+ .space 256, 0 /* Power-on class handler, */
+ /* not required here */
+not_a_tlb_miss:
+ synco /* TAKum03020 (but probably a good idea anyway.) */
+ /* Save original stack pointer into KCR1 */
+ putcon SP, KCR1
+
+ /* Save other original registers into reg_save_area */
+ movi reg_save_area, SP
+ st.q SP, SAVED_R2, r2
+ st.q SP, SAVED_R3, r3
+ st.q SP, SAVED_R4, r4
+ st.q SP, SAVED_R5, r5
+ st.q SP, SAVED_R6, r6
+ st.q SP, SAVED_R18, r18
+ gettr tr0, r3
+ st.q SP, SAVED_TR0, r3
+
+ /* Set args for Non-debug, Not a TLB miss class handler */
+ getcon EXPEVT, r2
+ movi ret_from_exception, r3
+ ori r3, 1, r3
+ movi EVENT_FAULT_NOT_TLB, r4
+ or SP, ZERO, r5
+ getcon KCR1, SP
+ pta handle_exception, tr0
+ blink tr0, ZERO
+
+ .balign 256
+ ! VBR+0x200
+ nop
+ .balign 256
+ ! VBR+0x300
+ nop
+ .balign 256
+ /*
+ * Instead of the natural .balign 1024 place RESVEC here
+ * respecting the final 1KB alignment.
+ */
+ .balign TEXT_SIZE
+ /*
+ * Instead of '.space 1024-TEXT_SIZE' place the RESVEC
+ * block making sure the final alignment is correct.
+ */
+tlb_miss:
+ synco /* TAKum03020 (but probably a good idea anyway.) */
+ putcon SP, KCR1
+ movi reg_save_area, SP
+ /* SP is guaranteed 32-byte aligned. */
+ st.q SP, TLB_SAVED_R0 , r0
+ st.q SP, TLB_SAVED_R1 , r1
+ st.q SP, SAVED_R2 , r2
+ st.q SP, SAVED_R3 , r3
+ st.q SP, SAVED_R4 , r4
+ st.q SP, SAVED_R5 , r5
+ st.q SP, SAVED_R6 , r6
+ st.q SP, SAVED_R18, r18
+
+ /* Save R25 for safety; as/ld may want to use it to achieve the call to
+ * the code in mm/tlbmiss.c */
+ st.q SP, TLB_SAVED_R25, r25
+ gettr tr0, r2
+ gettr tr1, r3
+ gettr tr2, r4
+ gettr tr3, r5
+ gettr tr4, r18
+ st.q SP, SAVED_TR0 , r2
+ st.q SP, TLB_SAVED_TR1 , r3
+ st.q SP, TLB_SAVED_TR2 , r4
+ st.q SP, TLB_SAVED_TR3 , r5
+ st.q SP, TLB_SAVED_TR4 , r18
+
+ pt do_fast_page_fault, tr0
+ getcon SSR, r2
+ getcon EXPEVT, r3
+ getcon TEA, r4
+ shlri r2, 30, r2
+ andi r2, 1, r2 /* r2 = SSR.MD */
+ blink tr0, LINK
+
+ pt fixup_to_invoke_general_handler, tr1
+
+ /* If the fast path handler fixed the fault, just drop through quickly
+ to the restore code right away to return to the excepting context.
+ */
+ beqi/u r2, 0, tr1
+
+fast_tlb_miss_restore:
+ ld.q SP, SAVED_TR0, r2
+ ld.q SP, TLB_SAVED_TR1, r3
+ ld.q SP, TLB_SAVED_TR2, r4
+
+ ld.q SP, TLB_SAVED_TR3, r5
+ ld.q SP, TLB_SAVED_TR4, r18
+
+ ptabs r2, tr0
+ ptabs r3, tr1
+ ptabs r4, tr2
+ ptabs r5, tr3
+ ptabs r18, tr4
+
+ ld.q SP, TLB_SAVED_R0, r0
+ ld.q SP, TLB_SAVED_R1, r1
+ ld.q SP, SAVED_R2, r2
+ ld.q SP, SAVED_R3, r3
+ ld.q SP, SAVED_R4, r4
+ ld.q SP, SAVED_R5, r5
+ ld.q SP, SAVED_R6, r6
+ ld.q SP, SAVED_R18, r18
+ ld.q SP, TLB_SAVED_R25, r25
+
+ getcon KCR1, SP
+ rte
+ nop /* for safety, in case the code is run on sh5-101 cut1.x */
+
+fixup_to_invoke_general_handler:
+
+ /* OK, new method. Restore stuff that's not expected to get saved into
+ the 'first-level' reg save area, then just fall through to setting
+ up the registers and calling the second-level handler. */
+
+ /* 2nd level expects r2,3,4,5,6,18,tr0 to be saved. So we must restore
+ r25,tr1-4 and save r6 to get into the right state. */
+
+ ld.q SP, TLB_SAVED_TR1, r3
+ ld.q SP, TLB_SAVED_TR2, r4
+ ld.q SP, TLB_SAVED_TR3, r5
+ ld.q SP, TLB_SAVED_TR4, r18
+ ld.q SP, TLB_SAVED_R25, r25
+
+ ld.q SP, TLB_SAVED_R0, r0
+ ld.q SP, TLB_SAVED_R1, r1
+
+ ptabs/u r3, tr1
+ ptabs/u r4, tr2
+ ptabs/u r5, tr3
+ ptabs/u r18, tr4
+
+ /* Set args for Non-debug, TLB miss class handler */
+ getcon EXPEVT, r2
+ movi ret_from_exception, r3
+ ori r3, 1, r3
+ movi EVENT_FAULT_TLB, r4
+ or SP, ZERO, r5
+ getcon KCR1, SP
+ pta handle_exception, tr0
+ blink tr0, ZERO
+
+/* NB TAKE GREAT CARE HERE TO ENSURE THAT THE INTERRUPT CODE
+ DOES END UP AT VBR+0x600 */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ .balign 256
+ /* VBR + 0x600 */
+
+interrupt:
+ synco /* TAKum03020 (but probably a good idea anyway.) */
+ /* Save original stack pointer into KCR1 */
+ putcon SP, KCR1
+
+ /* Save other original registers into reg_save_area */
+ movi reg_save_area, SP
+ st.q SP, SAVED_R2, r2
+ st.q SP, SAVED_R3, r3
+ st.q SP, SAVED_R4, r4
+ st.q SP, SAVED_R5, r5
+ st.q SP, SAVED_R6, r6
+ st.q SP, SAVED_R18, r18
+ gettr tr0, r3
+ st.q SP, SAVED_TR0, r3
+
+ /* Set args for interrupt class handler */
+ getcon INTEVT, r2
+ movi ret_from_irq, r3
+ ori r3, 1, r3
+ movi EVENT_INTERRUPT, r4
+ or SP, ZERO, r5
+ getcon KCR1, SP
+ pta handle_exception, tr0
+ blink tr0, ZERO
+ .balign TEXT_SIZE /* let's waste the bare minimum */
+
+LVBR_block_end: /* Marker. Used for total checking */
+
+ .balign 256
+LRESVEC_block:
+ /* Panic handler. Called with MMU off. Possible causes/actions:
+ * - Reset: Jump to program start.
+ * - Single Step: Turn off Single Step & return.
+ * - Others: Call panic handler, passing PC as arg.
+ * (this may need to be extended...)
+ */
+reset_or_panic:
+ synco /* TAKum03020 (but probably a good idea anyway.) */
+ putcon SP, DCR
+ /* First save r0-1 and tr0, as we need to use these */
+ movi resvec_save_area-CONFIG_PAGE_OFFSET, SP
+ st.q SP, 0, r0
+ st.q SP, 8, r1
+ gettr tr0, r0
+ st.q SP, 32, r0
+
+ /* Check cause */
+ getcon EXPEVT, r0
+ movi RESET_CAUSE, r1
+ sub r1, r0, r1 /* r1=0 if reset */
+ movi _stext-CONFIG_PAGE_OFFSET, r0
+ ori r0, 1, r0
+ ptabs r0, tr0
+ beqi r1, 0, tr0 /* Jump to start address if reset */
+
+ getcon EXPEVT, r0
+ movi DEBUGSS_CAUSE, r1
+ sub r1, r0, r1 /* r1=0 if single step */
+ pta single_step_panic, tr0
+ beqi r1, 0, tr0 /* jump if single step */
+
+ /* Now jump to where we save the registers. */
+ movi panic_stash_regs-CONFIG_PAGE_OFFSET, r1
+ ptabs r1, tr0
+ blink tr0, r63
+
+single_step_panic:
+ /* We are in a handler with Single Step set. We need to resume the
+ * handler, by turning on MMU & turning off Single Step. */
+ getcon SSR, r0
+ movi SR_MMU, r1
+ or r0, r1, r0
+ movi ~SR_SS, r1
+ and r0, r1, r0
+ putcon r0, SSR
+ /* Restore EXPEVT, as the rte won't do this */
+ getcon PEXPEVT, r0
+ putcon r0, EXPEVT
+ /* Restore regs */
+ ld.q SP, 32, r0
+ ptabs r0, tr0
+ ld.q SP, 0, r0
+ ld.q SP, 8, r1
+ getcon DCR, SP
+ synco
+ rte
+
+
+ .balign 256
+debug_exception:
+ synco /* TAKum03020 (but probably a good idea anyway.) */
+ /*
+ * Single step/software_break_point first level handler.
+ * Called with MMU off, so the first thing we do is enable it
+ * by doing an rte with appropriate SSR.
+ */
+ putcon SP, DCR
+ /* Save SSR & SPC, together with R0 & R1, as we need to use 2 regs. */
+ movi resvec_save_area-CONFIG_PAGE_OFFSET, SP
+
+ /* With the MMU off, we are bypassing the cache, so purge any
+ * data that will be made stale by the following stores.
+ */
+ ocbp SP, 0
+ synco
+
+ st.q SP, 0, r0
+ st.q SP, 8, r1
+ getcon SPC, r0
+ st.q SP, 16, r0
+ getcon SSR, r0
+ st.q SP, 24, r0
+
+ /* Enable MMU, block exceptions, set priv mode, disable single step */
+ movi SR_MMU | SR_BL | SR_MD, r1
+ or r0, r1, r0
+ movi ~SR_SS, r1
+ and r0, r1, r0
+ putcon r0, SSR
+ /* Force control to debug_exception_2 when rte is executed */
+ movi debug_exeception_2, r0
+ ori r0, 1, r0 /* force SHmedia, just in case */
+ putcon r0, SPC
+ getcon DCR, SP
+ synco
+ rte
+debug_exeception_2:
+ /* Restore saved regs */
+ putcon SP, KCR1
+ movi resvec_save_area, SP
+ ld.q SP, 24, r0
+ putcon r0, SSR
+ ld.q SP, 16, r0
+ putcon r0, SPC
+ ld.q SP, 0, r0
+ ld.q SP, 8, r1
+
+ /* Save other original registers into reg_save_area */
+ movi reg_save_area, SP
+ st.q SP, SAVED_R2, r2
+ st.q SP, SAVED_R3, r3
+ st.q SP, SAVED_R4, r4
+ st.q SP, SAVED_R5, r5
+ st.q SP, SAVED_R6, r6
+ st.q SP, SAVED_R18, r18
+ gettr tr0, r3
+ st.q SP, SAVED_TR0, r3
+
+ /* Set args for debug class handler */
+ getcon EXPEVT, r2
+ movi ret_from_exception, r3
+ ori r3, 1, r3
+ movi EVENT_DEBUG, r4
+ or SP, ZERO, r5
+ getcon KCR1, SP
+ pta handle_exception, tr0
+ blink tr0, ZERO
+
+ .balign 256
+debug_interrupt:
+ /* !!! WE COME HERE IN REAL MODE !!! */
+ /* Hook-up debug interrupt to allow various debugging options to be
+ * hooked into its handler. */
+ /* Save original stack pointer into KCR1 */
+ synco
+ putcon SP, KCR1
+ movi resvec_save_area-CONFIG_PAGE_OFFSET, SP
+ ocbp SP, 0
+ ocbp SP, 32
+ synco
+
+ /* Save other original registers into reg_save_area thru real addresses */
+ st.q SP, SAVED_R2, r2
+ st.q SP, SAVED_R3, r3
+ st.q SP, SAVED_R4, r4
+ st.q SP, SAVED_R5, r5
+ st.q SP, SAVED_R6, r6
+ st.q SP, SAVED_R18, r18
+ gettr tr0, r3
+ st.q SP, SAVED_TR0, r3
+
+ /* move (spc,ssr)->(pspc,pssr). The rte will shift
+ them back again, so that they look like the originals
+ as far as the real handler code is concerned. */
+ getcon spc, r6
+ putcon r6, pspc
+ getcon ssr, r6
+ putcon r6, pssr
+
+ ! construct useful SR for handle_exception
+ movi 3, r6
+ shlli r6, 30, r6
+ getcon sr, r18
+ or r18, r6, r6
+ putcon r6, ssr
+
+ ! SSR is now the current SR with the MD and MMU bits set
+ ! i.e. the rte will switch back to priv mode and put
+ ! the mmu back on
+
+ ! construct spc
+ movi handle_exception, r18
+ ori r18, 1, r18 ! for safety (do we need this?)
+ putcon r18, spc
+
+ /* Set args for Non-debug, Not a TLB miss class handler */
+
+ ! EXPEVT==0x80 is unused, so 'steal' this value to put the
+ ! debug interrupt handler in the vectoring table
+ movi 0x80, r2
+ movi ret_from_exception, r3
+ ori r3, 1, r3
+ movi EVENT_FAULT_NOT_TLB, r4
+
+ or SP, ZERO, r5
+ movi CONFIG_PAGE_OFFSET, r6
+ add r6, r5, r5
+ getcon KCR1, SP
+
+ synco ! for safety
+ rte ! -> handle_exception, switch back to priv mode again
+
+LRESVEC_block_end: /* Marker. Unused. */
+
+ .balign TEXT_SIZE
+
+/*
+ * Second level handler for VBR-based exceptions. Pre-handler.
+ * In common to all stack-frame sensitive handlers.
+ *
+ * Inputs:
+ * (KCR0) Current [current task union]
+ * (KCR1) Original SP
+ * (r2) INTEVT/EXPEVT
+ * (r3) appropriate return address
+ * (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault, 3=debug)
+ * (r5) Pointer to reg_save_area
+ * (SP) Original SP
+ *
+ * Available registers:
+ * (r6)
+ * (r18)
+ * (tr0)
+ *
+ */
+handle_exception:
+ /* Common 2nd level handler. */
+
+ /* First thing we need an appropriate stack pointer */
+ getcon SSR, r6
+ shlri r6, 30, r6
+ andi r6, 1, r6
+ pta stack_ok, tr0
+ bne r6, ZERO, tr0 /* Original stack pointer is fine */
+
+ /* Set stack pointer for user fault */
+ getcon KCR0, SP
+ movi THREAD_SIZE, r6 /* Point to the end */
+ add SP, r6, SP
+
+stack_ok:
+
+/* DEBUG : check for underflow/overflow of the kernel stack */
+ pta no_underflow, tr0
+ getcon KCR0, r6
+ movi 1024, r18
+ add r6, r18, r6
+ bge SP, r6, tr0 ! ? below 1k from bottom of stack : danger zone
+
+/* Just panic to cause a crash. */
+bad_sp:
+ ld.b r63, 0, r6
+ nop
+
+no_underflow:
+ pta bad_sp, tr0
+ getcon kcr0, r6
+ movi THREAD_SIZE, r18
+ add r18, r6, r6
+ bgt SP, r6, tr0 ! sp above the stack
+
+ /* Make some room for the BASIC frame. */
+ movi -(FRAME_SIZE), r6
+ add SP, r6, SP
+
+/* Could do this with no stalling if we had another spare register, but the
+ code below will be OK. */
+ ld.q r5, SAVED_R2, r6
+ ld.q r5, SAVED_R3, r18
+ st.q SP, FRAME_R(2), r6
+ ld.q r5, SAVED_R4, r6
+ st.q SP, FRAME_R(3), r18
+ ld.q r5, SAVED_R5, r18
+ st.q SP, FRAME_R(4), r6
+ ld.q r5, SAVED_R6, r6
+ st.q SP, FRAME_R(5), r18
+ ld.q r5, SAVED_R18, r18
+ st.q SP, FRAME_R(6), r6
+ ld.q r5, SAVED_TR0, r6
+ st.q SP, FRAME_R(18), r18
+ st.q SP, FRAME_T(0), r6
+
+ /* Keep old SP around */
+ getcon KCR1, r6
+
+ /* Save the rest of the general purpose registers */
+ st.q SP, FRAME_R(0), r0
+ st.q SP, FRAME_R(1), r1
+ st.q SP, FRAME_R(7), r7
+ st.q SP, FRAME_R(8), r8
+ st.q SP, FRAME_R(9), r9
+ st.q SP, FRAME_R(10), r10
+ st.q SP, FRAME_R(11), r11
+ st.q SP, FRAME_R(12), r12
+ st.q SP, FRAME_R(13), r13
+ st.q SP, FRAME_R(14), r14
+
+ /* SP is somewhere else */
+ st.q SP, FRAME_R(15), r6
+
+ st.q SP, FRAME_R(16), r16
+ st.q SP, FRAME_R(17), r17
+ /* r18 is saved earlier. */
+ st.q SP, FRAME_R(19), r19
+ st.q SP, FRAME_R(20), r20
+ st.q SP, FRAME_R(21), r21
+ st.q SP, FRAME_R(22), r22
+ st.q SP, FRAME_R(23), r23
+ st.q SP, FRAME_R(24), r24
+ st.q SP, FRAME_R(25), r25
+ st.q SP, FRAME_R(26), r26
+ st.q SP, FRAME_R(27), r27
+ st.q SP, FRAME_R(28), r28
+ st.q SP, FRAME_R(29), r29
+ st.q SP, FRAME_R(30), r30
+ st.q SP, FRAME_R(31), r31
+ st.q SP, FRAME_R(32), r32
+ st.q SP, FRAME_R(33), r33
+ st.q SP, FRAME_R(34), r34
+ st.q SP, FRAME_R(35), r35
+ st.q SP, FRAME_R(36), r36
+ st.q SP, FRAME_R(37), r37
+ st.q SP, FRAME_R(38), r38
+ st.q SP, FRAME_R(39), r39
+ st.q SP, FRAME_R(40), r40
+ st.q SP, FRAME_R(41), r41
+ st.q SP, FRAME_R(42), r42
+ st.q SP, FRAME_R(43), r43
+ st.q SP, FRAME_R(44), r44
+ st.q SP, FRAME_R(45), r45
+ st.q SP, FRAME_R(46), r46
+ st.q SP, FRAME_R(47), r47
+ st.q SP, FRAME_R(48), r48
+ st.q SP, FRAME_R(49), r49
+ st.q SP, FRAME_R(50), r50
+ st.q SP, FRAME_R(51), r51
+ st.q SP, FRAME_R(52), r52
+ st.q SP, FRAME_R(53), r53
+ st.q SP, FRAME_R(54), r54
+ st.q SP, FRAME_R(55), r55
+ st.q SP, FRAME_R(56), r56
+ st.q SP, FRAME_R(57), r57
+ st.q SP, FRAME_R(58), r58
+ st.q SP, FRAME_R(59), r59
+ st.q SP, FRAME_R(60), r60
+ st.q SP, FRAME_R(61), r61
+ st.q SP, FRAME_R(62), r62
+
+ /*
+ * Save the S* registers.
+ */
+ getcon SSR, r61
+ st.q SP, FRAME_S(FSSR), r61
+ getcon SPC, r62
+ st.q SP, FRAME_S(FSPC), r62
+ movi -1, r62 /* Reset syscall_nr */
+ st.q SP, FRAME_S(FSYSCALL_ID), r62
+
+ /* Save the rest of the target registers */
+ gettr tr1, r6
+ st.q SP, FRAME_T(1), r6
+ gettr tr2, r6
+ st.q SP, FRAME_T(2), r6
+ gettr tr3, r6
+ st.q SP, FRAME_T(3), r6
+ gettr tr4, r6
+ st.q SP, FRAME_T(4), r6
+ gettr tr5, r6
+ st.q SP, FRAME_T(5), r6
+ gettr tr6, r6
+ st.q SP, FRAME_T(6), r6
+ gettr tr7, r6
+ st.q SP, FRAME_T(7), r6
+
+ ! setup FP so that unwinder can wind back through nested kernel mode
+ ! exceptions
+ add SP, ZERO, r14
+
+#ifdef CONFIG_POOR_MANS_STRACE
+ /* We've pushed all the registers now, so only r2-r4 hold anything
+ * useful. Move them into callee save registers */
+ or r2, ZERO, r28
+ or r3, ZERO, r29
+ or r4, ZERO, r30
+
+ /* Preserve r2 as the event code */
+ movi evt_debug, r3
+ ori r3, 1, r3
+ ptabs r3, tr0
+
+ or SP, ZERO, r6
+ getcon TRA, r5
+ blink tr0, LINK
+
+ or r28, ZERO, r2
+ or r29, ZERO, r3
+ or r30, ZERO, r4
+#endif
+
+ /* For syscall and debug race condition, get TRA now */
+ getcon TRA, r5
+
+ /* We are in a safe position to turn SR.BL off, but set IMASK=0xf
+ * Also set FD, to catch FPU usage in the kernel.
+ *
+ * benedict.gaster@superh.com 29/07/2002
+ *
+ * On all SH5-101 revisions it is unsafe to raise the IMASK and at the
+ * same time change BL from 1->0, as any pending interrupt of a level
+ * higher than he previous value of IMASK will leak through and be
+ * taken unexpectedly.
+ *
+ * To avoid this we raise the IMASK and then issue another PUTCON to
+ * enable interrupts.
+ */
+ getcon SR, r6
+ movi SR_IMASK | SR_FD, r7
+ or r6, r7, r6
+ putcon r6, SR
+ movi SR_UNBLOCK_EXC, r7
+ and r6, r7, r6
+ putcon r6, SR
+
+
+ /* Now call the appropriate 3rd level handler */
+ or r3, ZERO, LINK
+ movi trap_jtable, r3
+ shlri r2, 3, r2
+ ldx.l r2, r3, r3
+ shlri r2, 2, r2
+ ptabs r3, tr0
+ or SP, ZERO, r3
+ blink tr0, ZERO
+
+/*
+ * Second level handler for VBR-based exceptions. Post-handlers.
+ *
+ * Post-handlers for interrupts (ret_from_irq), exceptions
+ * (ret_from_exception) and common reentrance doors (restore_all
+ * to get back to the original context, ret_from_syscall loop to
+ * check kernel exiting).
+ *
+ * ret_with_reschedule and work_notifysig are an inner lables of
+ * the ret_from_syscall loop.
+ *
+ * In common to all stack-frame sensitive handlers.
+ *
+ * Inputs:
+ * (SP) struct pt_regs *, original register's frame pointer (basic)
+ *
+ */
+ .global ret_from_irq
+ret_from_irq:
+#ifdef CONFIG_POOR_MANS_STRACE
+ pta evt_debug_ret_from_irq, tr0
+ ori SP, 0, r2
+ blink tr0, LINK
+#endif
+ ld.q SP, FRAME_S(FSSR), r6
+ shlri r6, 30, r6
+ andi r6, 1, r6
+ pta resume_kernel, tr0
+ bne r6, ZERO, tr0 /* no further checks */
+ STI()
+ pta ret_with_reschedule, tr0
+ blink tr0, ZERO /* Do not check softirqs */
+
+ .global ret_from_exception
+ret_from_exception:
+ preempt_stop()
+
+#ifdef CONFIG_POOR_MANS_STRACE
+ pta evt_debug_ret_from_exc, tr0
+ ori SP, 0, r2
+ blink tr0, LINK
+#endif
+
+ ld.q SP, FRAME_S(FSSR), r6
+ shlri r6, 30, r6
+ andi r6, 1, r6
+ pta resume_kernel, tr0
+ bne r6, ZERO, tr0 /* no further checks */
+
+ /* Check softirqs */
+
+#ifdef CONFIG_PREEMPT
+ pta ret_from_syscall, tr0
+ blink tr0, ZERO
+
+resume_kernel:
+ pta restore_all, tr0
+
+ getcon KCR0, r6
+ ld.l r6, TI_PRE_COUNT, r7
+ beq/u r7, ZERO, tr0
+
+need_resched:
+ ld.l r6, TI_FLAGS, r7
+ movi (1 << TIF_NEED_RESCHED), r8
+ and r8, r7, r8
+ bne r8, ZERO, tr0
+
+ getcon SR, r7
+ andi r7, 0xf0, r7
+ bne r7, ZERO, tr0
+
+ movi ((PREEMPT_ACTIVE >> 16) & 65535), r8
+ shori (PREEMPT_ACTIVE & 65535), r8
+ st.l r6, TI_PRE_COUNT, r8
+
+ STI()
+ movi schedule, r7
+ ori r7, 1, r7
+ ptabs r7, tr1
+ blink tr1, LINK
+
+ st.l r6, TI_PRE_COUNT, ZERO
+ CLI()
+
+ pta need_resched, tr1
+ blink tr1, ZERO
+#endif
+
+ .global ret_from_syscall
+ret_from_syscall:
+
+ret_with_reschedule:
+ getcon KCR0, r6 ! r6 contains current_thread_info
+ ld.l r6, TI_FLAGS, r7 ! r7 contains current_thread_info->flags
+
+ movi _TIF_NEED_RESCHED, r8
+ and r8, r7, r8
+ pta work_resched, tr0
+ bne r8, ZERO, tr0
+
+ pta restore_all, tr1
+
+ movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
+ and r8, r7, r8
+ pta work_notifysig, tr0
+ bne r8, ZERO, tr0
+
+ blink tr1, ZERO
+
+work_resched:
+ pta ret_from_syscall, tr0
+ gettr tr0, LINK
+ movi schedule, r6
+ ptabs r6, tr0
+ blink tr0, ZERO /* Call schedule(), return on top */
+
+work_notifysig:
+ gettr tr1, LINK
+
+ movi do_signal, r6
+ ptabs r6, tr0
+ or SP, ZERO, r2
+ or ZERO, ZERO, r3
+ blink tr0, LINK /* Call do_signal(regs, 0), return here */
+
+restore_all:
+ /* Do prefetches */
+
+ ld.q SP, FRAME_T(0), r6
+ ld.q SP, FRAME_T(1), r7
+ ld.q SP, FRAME_T(2), r8
+ ld.q SP, FRAME_T(3), r9
+ ptabs r6, tr0
+ ptabs r7, tr1
+ ptabs r8, tr2
+ ptabs r9, tr3
+ ld.q SP, FRAME_T(4), r6
+ ld.q SP, FRAME_T(5), r7
+ ld.q SP, FRAME_T(6), r8
+ ld.q SP, FRAME_T(7), r9
+ ptabs r6, tr4
+ ptabs r7, tr5
+ ptabs r8, tr6
+ ptabs r9, tr7
+
+ ld.q SP, FRAME_R(0), r0
+ ld.q SP, FRAME_R(1), r1
+ ld.q SP, FRAME_R(2), r2
+ ld.q SP, FRAME_R(3), r3
+ ld.q SP, FRAME_R(4), r4
+ ld.q SP, FRAME_R(5), r5
+ ld.q SP, FRAME_R(6), r6
+ ld.q SP, FRAME_R(7), r7
+ ld.q SP, FRAME_R(8), r8
+ ld.q SP, FRAME_R(9), r9
+ ld.q SP, FRAME_R(10), r10
+ ld.q SP, FRAME_R(11), r11
+ ld.q SP, FRAME_R(12), r12
+ ld.q SP, FRAME_R(13), r13
+ ld.q SP, FRAME_R(14), r14
+
+ ld.q SP, FRAME_R(16), r16
+ ld.q SP, FRAME_R(17), r17
+ ld.q SP, FRAME_R(18), r18
+ ld.q SP, FRAME_R(19), r19
+ ld.q SP, FRAME_R(20), r20
+ ld.q SP, FRAME_R(21), r21
+ ld.q SP, FRAME_R(22), r22
+ ld.q SP, FRAME_R(23), r23
+ ld.q SP, FRAME_R(24), r24
+ ld.q SP, FRAME_R(25), r25
+ ld.q SP, FRAME_R(26), r26
+ ld.q SP, FRAME_R(27), r27
+ ld.q SP, FRAME_R(28), r28
+ ld.q SP, FRAME_R(29), r29
+ ld.q SP, FRAME_R(30), r30
+ ld.q SP, FRAME_R(31), r31
+ ld.q SP, FRAME_R(32), r32
+ ld.q SP, FRAME_R(33), r33
+ ld.q SP, FRAME_R(34), r34
+ ld.q SP, FRAME_R(35), r35
+ ld.q SP, FRAME_R(36), r36
+ ld.q SP, FRAME_R(37), r37
+ ld.q SP, FRAME_R(38), r38
+ ld.q SP, FRAME_R(39), r39
+ ld.q SP, FRAME_R(40), r40
+ ld.q SP, FRAME_R(41), r41
+ ld.q SP, FRAME_R(42), r42
+ ld.q SP, FRAME_R(43), r43
+ ld.q SP, FRAME_R(44), r44
+ ld.q SP, FRAME_R(45), r45
+ ld.q SP, FRAME_R(46), r46
+ ld.q SP, FRAME_R(47), r47
+ ld.q SP, FRAME_R(48), r48
+ ld.q SP, FRAME_R(49), r49
+ ld.q SP, FRAME_R(50), r50
+ ld.q SP, FRAME_R(51), r51
+ ld.q SP, FRAME_R(52), r52
+ ld.q SP, FRAME_R(53), r53
+ ld.q SP, FRAME_R(54), r54
+ ld.q SP, FRAME_R(55), r55
+ ld.q SP, FRAME_R(56), r56
+ ld.q SP, FRAME_R(57), r57
+ ld.q SP, FRAME_R(58), r58
+
+ getcon SR, r59
+ movi SR_BLOCK_EXC, r60
+ or r59, r60, r59
+ putcon r59, SR /* SR.BL = 1, keep nesting out */
+ ld.q SP, FRAME_S(FSSR), r61
+ ld.q SP, FRAME_S(FSPC), r62
+ movi SR_ASID_MASK, r60
+ and r59, r60, r59
+ andc r61, r60, r61 /* Clear out older ASID */
+ or r59, r61, r61 /* Retain current ASID */
+ putcon r61, SSR
+ putcon r62, SPC
+
+ /* Ignore FSYSCALL_ID */
+
+ ld.q SP, FRAME_R(59), r59
+ ld.q SP, FRAME_R(60), r60
+ ld.q SP, FRAME_R(61), r61
+ ld.q SP, FRAME_R(62), r62
+
+ /* Last touch */
+ ld.q SP, FRAME_R(15), SP
+ rte
+ nop
+
+/*
+ * Third level handlers for VBR-based exceptions. Adapting args to
+ * and/or deflecting to fourth level handlers.
+ *
+ * Fourth level handlers interface.
+ * Most are C-coded handlers directly pointed by the trap_jtable.
+ * (Third = Fourth level)
+ * Inputs:
+ * (r2) fault/interrupt code, entry number (e.g. NMI = 14,
+ * IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...)
+ * (r3) struct pt_regs *, original register's frame pointer
+ * (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault)
+ * (r5) TRA control register (for syscall/debug benefit only)
+ * (LINK) return address
+ * (SP) = r3
+ *
+ * Kernel TLB fault handlers will get a slightly different interface.
+ * (r2) struct pt_regs *, original register's frame pointer
+ * (r3) writeaccess, whether it's a store fault as opposed to load fault
+ * (r4) execaccess, whether it's a ITLB fault as opposed to DTLB fault
+ * (r5) Effective Address of fault
+ * (LINK) return address
+ * (SP) = r2
+ *
+ * fpu_error_or_IRQ? is a helper to deflect to the right cause.
+ *
+ */
+tlb_miss_load:
+ or SP, ZERO, r2
+ or ZERO, ZERO, r3 /* Read */
+ or ZERO, ZERO, r4 /* Data */
+ getcon TEA, r5
+ pta call_do_page_fault, tr0
+ beq ZERO, ZERO, tr0
+
+tlb_miss_store:
+ or SP, ZERO, r2
+ movi 1, r3 /* Write */
+ or ZERO, ZERO, r4 /* Data */
+ getcon TEA, r5
+ pta call_do_page_fault, tr0
+ beq ZERO, ZERO, tr0
+
+itlb_miss_or_IRQ:
+ pta its_IRQ, tr0
+ beqi/u r4, EVENT_INTERRUPT, tr0
+ or SP, ZERO, r2
+ or ZERO, ZERO, r3 /* Read */
+ movi 1, r4 /* Text */
+ getcon TEA, r5
+ /* Fall through */
+
+call_do_page_fault:
+ movi do_page_fault, r6
+ ptabs r6, tr0
+ blink tr0, ZERO
+
+fpu_error_or_IRQA:
+ pta its_IRQ, tr0
+ beqi/l r4, EVENT_INTERRUPT, tr0
+#ifdef CONFIG_SH_FPU
+ movi do_fpu_state_restore, r6
+#else
+ movi do_exception_error, r6
+#endif
+ ptabs r6, tr0
+ blink tr0, ZERO
+
+fpu_error_or_IRQB:
+ pta its_IRQ, tr0
+ beqi/l r4, EVENT_INTERRUPT, tr0
+#ifdef CONFIG_SH_FPU
+ movi do_fpu_state_restore, r6
+#else
+ movi do_exception_error, r6
+#endif
+ ptabs r6, tr0
+ blink tr0, ZERO
+
+its_IRQ:
+ movi do_IRQ, r6
+ ptabs r6, tr0
+ blink tr0, ZERO
+
+/*
+ * system_call/unknown_trap third level handler:
+ *
+ * Inputs:
+ * (r2) fault/interrupt code, entry number (TRAP = 11)
+ * (r3) struct pt_regs *, original register's frame pointer
+ * (r4) Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault)
+ * (r5) TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr)
+ * (SP) = r3
+ * (LINK) return address: ret_from_exception
+ * (*r3) Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7)
+ *
+ * Outputs:
+ * (*r3) Syscall reply (Saved r2)
+ * (LINK) In case of syscall only it can be scrapped.
+ * Common second level post handler will be ret_from_syscall.
+ * Common (non-trace) exit point to that is syscall_ret (saving
+ * result to r2). Common bad exit point is syscall_bad (returning
+ * ENOSYS then saved to r2).
+ *
+ */
+
+unknown_trap:
+ /* Unknown Trap or User Trace */
+ movi do_unknown_trapa, r6
+ ptabs r6, tr0
+ ld.q r3, FRAME_R(9), r2 /* r2 = #arg << 16 | syscall # */
+ andi r2, 0x1ff, r2 /* r2 = syscall # */
+ blink tr0, LINK
+
+ pta syscall_ret, tr0
+ blink tr0, ZERO
+
+ /* New syscall implementation*/
+system_call:
+ pta unknown_trap, tr0
+ or r5, ZERO, r4 /* TRA (=r5) -> r4 */
+ shlri r4, 20, r4
+ bnei r4, 1, tr0 /* unknown_trap if not 0x1yzzzz */
+
+ /* It's a system call */
+ st.q r3, FRAME_S(FSYSCALL_ID), r5 /* ID (0x1yzzzz) -> stack */
+ andi r5, 0x1ff, r5 /* syscall # -> r5 */
+
+ STI()
+
+ pta syscall_allowed, tr0
+ movi NR_syscalls - 1, r4 /* Last valid */
+ bgeu/l r4, r5, tr0
+
+syscall_bad:
+ /* Return ENOSYS ! */
+ movi -(ENOSYS), r2 /* Fall-through */
+
+ .global syscall_ret
+syscall_ret:
+ st.q SP, FRAME_R(9), r2 /* Expecting SP back to BASIC frame */
+
+#ifdef CONFIG_POOR_MANS_STRACE
+ /* nothing useful in registers at this point */
+
+ movi evt_debug2, r5
+ ori r5, 1, r5
+ ptabs r5, tr0
+ ld.q SP, FRAME_R(9), r2
+ or SP, ZERO, r3
+ blink tr0, LINK
+#endif
+
+ ld.q SP, FRAME_S(FSPC), r2
+ addi r2, 4, r2 /* Move PC, being pre-execution event */
+ st.q SP, FRAME_S(FSPC), r2
+ pta ret_from_syscall, tr0
+ blink tr0, ZERO
+
+
+/* A different return path for ret_from_fork, because we now need
+ * to call schedule_tail with the later kernels. Because prev is
+ * loaded into r2 by switch_to() means we can just call it straight away
+ */
+
+.global ret_from_fork
+ret_from_fork:
+
+ movi schedule_tail,r5
+ ori r5, 1, r5
+ ptabs r5, tr0
+ blink tr0, LINK
+
+#ifdef CONFIG_POOR_MANS_STRACE
+ /* nothing useful in registers at this point */
+
+ movi evt_debug2, r5
+ ori r5, 1, r5
+ ptabs r5, tr0
+ ld.q SP, FRAME_R(9), r2
+ or SP, ZERO, r3
+ blink tr0, LINK
+#endif
+
+ ld.q SP, FRAME_S(FSPC), r2
+ addi r2, 4, r2 /* Move PC, being pre-execution event */
+ st.q SP, FRAME_S(FSPC), r2
+ pta ret_from_syscall, tr0
+ blink tr0, ZERO
+
+
+
+syscall_allowed:
+ /* Use LINK to deflect the exit point, default is syscall_ret */
+ pta syscall_ret, tr0
+ gettr tr0, LINK
+ pta syscall_notrace, tr0
+
+ getcon KCR0, r2
+ ld.l r2, TI_FLAGS, r4
+ movi (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT), r6
+ and r6, r4, r6
+ beq/l r6, ZERO, tr0
+
+ /* Trace it by calling syscall_trace before and after */
+ movi syscall_trace, r4
+ or SP, ZERO, r2
+ or ZERO, ZERO, r3
+ ptabs r4, tr0
+ blink tr0, LINK
+
+ /* Reload syscall number as r5 is trashed by syscall_trace */
+ ld.q SP, FRAME_S(FSYSCALL_ID), r5
+ andi r5, 0x1ff, r5
+
+ pta syscall_ret_trace, tr0
+ gettr tr0, LINK
+
+syscall_notrace:
+ /* Now point to the appropriate 4th level syscall handler */
+ movi sys_call_table, r4
+ shlli r5, 2, r5
+ ldx.l r4, r5, r5
+ ptabs r5, tr0
+
+ /* Prepare original args */
+ ld.q SP, FRAME_R(2), r2
+ ld.q SP, FRAME_R(3), r3
+ ld.q SP, FRAME_R(4), r4
+ ld.q SP, FRAME_R(5), r5
+ ld.q SP, FRAME_R(6), r6
+ ld.q SP, FRAME_R(7), r7
+
+ /* And now the trick for those syscalls requiring regs * ! */
+ or SP, ZERO, r8
+
+ /* Call it */
+ blink tr0, ZERO /* LINK is already properly set */
+
+syscall_ret_trace:
+ /* We get back here only if under trace */
+ st.q SP, FRAME_R(9), r2 /* Save return value */
+
+ movi syscall_trace, LINK
+ or SP, ZERO, r2
+ movi 1, r3
+ ptabs LINK, tr0
+ blink tr0, LINK
+
+ /* This needs to be done after any syscall tracing */
+ ld.q SP, FRAME_S(FSPC), r2
+ addi r2, 4, r2 /* Move PC, being pre-execution event */
+ st.q SP, FRAME_S(FSPC), r2
+
+ pta ret_from_syscall, tr0
+ blink tr0, ZERO /* Resume normal return sequence */
+
+/*
+ * --- Switch to running under a particular ASID and return the previous ASID value
+ * --- The caller is assumed to have done a cli before calling this.
+ *
+ * Input r2 : new ASID
+ * Output r2 : old ASID
+ */
+
+ .global switch_and_save_asid
+switch_and_save_asid:
+ getcon sr, r0
+ movi 255, r4
+ shlli r4, 16, r4 /* r4 = mask to select ASID */
+ and r0, r4, r3 /* r3 = shifted old ASID */
+ andi r2, 255, r2 /* mask down new ASID */
+ shlli r2, 16, r2 /* align new ASID against SR.ASID */
+ andc r0, r4, r0 /* efface old ASID from SR */
+ or r0, r2, r0 /* insert the new ASID */
+ putcon r0, ssr
+ movi 1f, r0
+ putcon r0, spc
+ rte
+ nop
+1:
+ ptabs LINK, tr0
+ shlri r3, 16, r2 /* r2 = old ASID */
+ blink tr0, r63
+
+ .global route_to_panic_handler
+route_to_panic_handler:
+ /* Switch to real mode, goto panic_handler, don't return. Useful for
+ last-chance debugging, e.g. if no output wants to go to the console.
+ */
+
+ movi panic_handler - CONFIG_PAGE_OFFSET, r1
+ ptabs r1, tr0
+ pta 1f, tr1
+ gettr tr1, r0
+ putcon r0, spc
+ getcon sr, r0
+ movi 1, r1
+ shlli r1, 31, r1
+ andc r0, r1, r0
+ putcon r0, ssr
+ rte
+ nop
+1: /* Now in real mode */
+ blink tr0, r63
+ nop
+
+ .global peek_real_address_q
+peek_real_address_q:
+ /* Two args:
+ r2 : real mode address to peek
+ r2(out) : result quadword
+
+ This is provided as a cheapskate way of manipulating device
+ registers for debugging (to avoid the need to onchip_remap the debug
+ module, and to avoid the need to onchip_remap the watchpoint
+ controller in a way that identity maps sufficient bits to avoid the
+ SH5-101 cut2 silicon defect).
+
+ This code is not performance critical
+ */
+
+ add.l r2, r63, r2 /* sign extend address */
+ getcon sr, r0 /* r0 = saved original SR */
+ movi 1, r1
+ shlli r1, 28, r1
+ or r0, r1, r1 /* r0 with block bit set */
+ putcon r1, sr /* now in critical section */
+ movi 1, r36
+ shlli r36, 31, r36
+ andc r1, r36, r1 /* turn sr.mmu off in real mode section */
+
+ putcon r1, ssr
+ movi .peek0 - CONFIG_PAGE_OFFSET, r36 /* real mode target address */
+ movi 1f, r37 /* virtual mode return addr */
+ putcon r36, spc
+
+ synco
+ rte
+ nop
+
+.peek0: /* come here in real mode, don't touch caches!!
+ still in critical section (sr.bl==1) */
+ putcon r0, ssr
+ putcon r37, spc
+ /* Here's the actual peek. If the address is bad, all bets are now off
+ * what will happen (handlers invoked in real-mode = bad news) */
+ ld.q r2, 0, r2
+ synco
+ rte /* Back to virtual mode */
+ nop
+
+1:
+ ptabs LINK, tr0
+ blink tr0, r63
+
+ .global poke_real_address_q
+poke_real_address_q:
+ /* Two args:
+ r2 : real mode address to poke
+ r3 : quadword value to write.
+
+ This is provided as a cheapskate way of manipulating device
+ registers for debugging (to avoid the need to onchip_remap the debug
+ module, and to avoid the need to onchip_remap the watchpoint
+ controller in a way that identity maps sufficient bits to avoid the
+ SH5-101 cut2 silicon defect).
+
+ This code is not performance critical
+ */
+
+ add.l r2, r63, r2 /* sign extend address */
+ getcon sr, r0 /* r0 = saved original SR */
+ movi 1, r1
+ shlli r1, 28, r1
+ or r0, r1, r1 /* r0 with block bit set */
+ putcon r1, sr /* now in critical section */
+ movi 1, r36
+ shlli r36, 31, r36
+ andc r1, r36, r1 /* turn sr.mmu off in real mode section */
+
+ putcon r1, ssr
+ movi .poke0-CONFIG_PAGE_OFFSET, r36 /* real mode target address */
+ movi 1f, r37 /* virtual mode return addr */
+ putcon r36, spc
+
+ synco
+ rte
+ nop
+
+.poke0: /* come here in real mode, don't touch caches!!
+ still in critical section (sr.bl==1) */
+ putcon r0, ssr
+ putcon r37, spc
+ /* Here's the actual poke. If the address is bad, all bets are now off
+ * what will happen (handlers invoked in real-mode = bad news) */
+ st.q r2, 0, r3
+ synco
+ rte /* Back to virtual mode */
+ nop
+
+1:
+ ptabs LINK, tr0
+ blink tr0, r63
+
+/*
+ * --- User Access Handling Section
+ */
+
+/*
+ * User Access support. It all moved to non inlined Assembler
+ * functions in here.
+ *
+ * __kernel_size_t __copy_user(void *__to, const void *__from,
+ * __kernel_size_t __n)
+ *
+ * Inputs:
+ * (r2) target address
+ * (r3) source address
+ * (r4) size in bytes
+ *
+ * Ouputs:
+ * (*r2) target data
+ * (r2) non-copied bytes
+ *
+ * If a fault occurs on the user pointer, bail out early and return the
+ * number of bytes not copied in r2.
+ * Strategy : for large blocks, call a real memcpy function which can
+ * move >1 byte at a time using unaligned ld/st instructions, and can
+ * manipulate the cache using prefetch + alloco to improve the speed
+ * further. If a fault occurs in that function, just revert to the
+ * byte-by-byte approach used for small blocks; this is rare so the
+ * performance hit for that case does not matter.
+ *
+ * For small blocks it's not worth the overhead of setting up and calling
+ * the memcpy routine; do the copy a byte at a time.
+ *
+ */
+ .global __copy_user
+__copy_user:
+ pta __copy_user_byte_by_byte, tr1
+ movi 16, r0 ! this value is a best guess, should tune it by benchmarking
+ bge/u r0, r4, tr1
+ pta copy_user_memcpy, tr0
+ addi SP, -32, SP
+ /* Save arguments in case we have to fix-up unhandled page fault */
+ st.q SP, 0, r2
+ st.q SP, 8, r3
+ st.q SP, 16, r4
+ st.q SP, 24, r35 ! r35 is callee-save
+ /* Save LINK in a register to reduce RTS time later (otherwise
+ ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */
+ ori LINK, 0, r35
+ blink tr0, LINK
+
+ /* Copy completed normally if we get back here */
+ ptabs r35, tr0
+ ld.q SP, 24, r35
+ /* don't restore r2-r4, pointless */
+ /* set result=r2 to zero as the copy must have succeeded. */
+ or r63, r63, r2
+ addi SP, 32, SP
+ blink tr0, r63 ! RTS
+
+ .global __copy_user_fixup
+__copy_user_fixup:
+ /* Restore stack frame */
+ ori r35, 0, LINK
+ ld.q SP, 24, r35
+ ld.q SP, 16, r4
+ ld.q SP, 8, r3
+ ld.q SP, 0, r2
+ addi SP, 32, SP
+ /* Fall through to original code, in the 'same' state we entered with */
+
+/* The slow byte-by-byte method is used if the fast copy traps due to a bad
+ user address. In that rare case, the speed drop can be tolerated. */
+__copy_user_byte_by_byte:
+ pta ___copy_user_exit, tr1
+ pta ___copy_user1, tr0
+ beq/u r4, r63, tr1 /* early exit for zero length copy */
+ sub r2, r3, r0
+ addi r0, -1, r0
+
+___copy_user1:
+ ld.b r3, 0, r5 /* Fault address 1 */
+
+ /* Could rewrite this to use just 1 add, but the second comes 'free'
+ due to load latency */
+ addi r3, 1, r3
+ addi r4, -1, r4 /* No real fixup required */
+___copy_user2:
+ stx.b r3, r0, r5 /* Fault address 2 */
+ bne r4, ZERO, tr0
+
+___copy_user_exit:
+ or r4, ZERO, r2
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+/*
+ * __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
+ *
+ * Inputs:
+ * (r2) target address
+ * (r3) size in bytes
+ *
+ * Ouputs:
+ * (*r2) zero-ed target data
+ * (r2) non-zero-ed bytes
+ */
+ .global __clear_user
+__clear_user:
+ pta ___clear_user_exit, tr1
+ pta ___clear_user1, tr0
+ beq/u r3, r63, tr1
+
+___clear_user1:
+ st.b r2, 0, ZERO /* Fault address */
+ addi r2, 1, r2
+ addi r3, -1, r3 /* No real fixup required */
+ bne r3, ZERO, tr0
+
+___clear_user_exit:
+ or r3, ZERO, r2
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+/*
+ * int __strncpy_from_user(unsigned long __dest, unsigned long __src,
+ * int __count)
+ *
+ * Inputs:
+ * (r2) target address
+ * (r3) source address
+ * (r4) maximum size in bytes
+ *
+ * Ouputs:
+ * (*r2) copied data
+ * (r2) -EFAULT (in case of faulting)
+ * copied data (otherwise)
+ */
+ .global __strncpy_from_user
+__strncpy_from_user:
+ pta ___strncpy_from_user1, tr0
+ pta ___strncpy_from_user_done, tr1
+ or r4, ZERO, r5 /* r5 = original count */
+ beq/u r4, r63, tr1 /* early exit if r4==0 */
+ movi -(EFAULT), r6 /* r6 = reply, no real fixup */
+ or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */
+
+___strncpy_from_user1:
+ ld.b r3, 0, r7 /* Fault address: only in reading */
+ st.b r2, 0, r7
+ addi r2, 1, r2
+ addi r3, 1, r3
+ beq/u ZERO, r7, tr1
+ addi r4, -1, r4 /* return real number of copied bytes */
+ bne/l ZERO, r4, tr0
+
+___strncpy_from_user_done:
+ sub r5, r4, r6 /* If done, return copied */
+
+___strncpy_from_user_exit:
+ or r6, ZERO, r2
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+/*
+ * extern long __strnlen_user(const char *__s, long __n)
+ *
+ * Inputs:
+ * (r2) source address
+ * (r3) source size in bytes
+ *
+ * Ouputs:
+ * (r2) -EFAULT (in case of faulting)
+ * string length (otherwise)
+ */
+ .global __strnlen_user
+__strnlen_user:
+ pta ___strnlen_user_set_reply, tr0
+ pta ___strnlen_user1, tr1
+ or ZERO, ZERO, r5 /* r5 = counter */
+ movi -(EFAULT), r6 /* r6 = reply, no real fixup */
+ or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */
+ beq r3, ZERO, tr0
+
+___strnlen_user1:
+ ldx.b r2, r5, r7 /* Fault address: only in reading */
+ addi r3, -1, r3 /* No real fixup */
+ addi r5, 1, r5
+ beq r3, ZERO, tr0
+ bne r7, ZERO, tr1
+! The line below used to be active. This meant led to a junk byte lying between each pair
+! of entries in the argv & envp structures in memory. Whilst the program saw the right data
+! via the argv and envp arguments to main, it meant the 'flat' representation visible through
+! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example.
+! addi r5, 1, r5 /* Include '\0' */
+
+___strnlen_user_set_reply:
+ or r5, ZERO, r6 /* If done, return counter */
+
+___strnlen_user_exit:
+ or r6, ZERO, r2
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+/*
+ * extern long __get_user_asm_?(void *val, long addr)
+ *
+ * Inputs:
+ * (r2) dest address
+ * (r3) source address (in User Space)
+ *
+ * Ouputs:
+ * (r2) -EFAULT (faulting)
+ * 0 (not faulting)
+ */
+ .global __get_user_asm_b
+__get_user_asm_b:
+ or r2, ZERO, r4
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___get_user_asm_b1:
+ ld.b r3, 0, r5 /* r5 = data */
+ st.b r4, 0, r5
+ or ZERO, ZERO, r2
+
+___get_user_asm_b_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __get_user_asm_w
+__get_user_asm_w:
+ or r2, ZERO, r4
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___get_user_asm_w1:
+ ld.w r3, 0, r5 /* r5 = data */
+ st.w r4, 0, r5
+ or ZERO, ZERO, r2
+
+___get_user_asm_w_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __get_user_asm_l
+__get_user_asm_l:
+ or r2, ZERO, r4
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___get_user_asm_l1:
+ ld.l r3, 0, r5 /* r5 = data */
+ st.l r4, 0, r5
+ or ZERO, ZERO, r2
+
+___get_user_asm_l_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __get_user_asm_q
+__get_user_asm_q:
+ or r2, ZERO, r4
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___get_user_asm_q1:
+ ld.q r3, 0, r5 /* r5 = data */
+ st.q r4, 0, r5
+ or ZERO, ZERO, r2
+
+___get_user_asm_q_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+/*
+ * extern long __put_user_asm_?(void *pval, long addr)
+ *
+ * Inputs:
+ * (r2) kernel pointer to value
+ * (r3) dest address (in User Space)
+ *
+ * Ouputs:
+ * (r2) -EFAULT (faulting)
+ * 0 (not faulting)
+ */
+ .global __put_user_asm_b
+__put_user_asm_b:
+ ld.b r2, 0, r4 /* r4 = data */
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___put_user_asm_b1:
+ st.b r3, 0, r4
+ or ZERO, ZERO, r2
+
+___put_user_asm_b_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __put_user_asm_w
+__put_user_asm_w:
+ ld.w r2, 0, r4 /* r4 = data */
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___put_user_asm_w1:
+ st.w r3, 0, r4
+ or ZERO, ZERO, r2
+
+___put_user_asm_w_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __put_user_asm_l
+__put_user_asm_l:
+ ld.l r2, 0, r4 /* r4 = data */
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___put_user_asm_l1:
+ st.l r3, 0, r4
+ or ZERO, ZERO, r2
+
+___put_user_asm_l_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+
+ .global __put_user_asm_q
+__put_user_asm_q:
+ ld.q r2, 0, r4 /* r4 = data */
+ movi -(EFAULT), r2 /* r2 = reply, no real fixup */
+
+___put_user_asm_q1:
+ st.q r3, 0, r4
+ or ZERO, ZERO, r2
+
+___put_user_asm_q_exit:
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
+panic_stash_regs:
+ /* The idea is : when we get an unhandled panic, we dump the registers
+ to a known memory location, the just sit in a tight loop.
+ This allows the human to look at the memory region through the GDB
+ session (assuming the debug module's SHwy initiator isn't locked up
+ or anything), to hopefully analyze the cause of the panic. */
+
+ /* On entry, former r15 (SP) is in DCR
+ former r0 is at resvec_saved_area + 0
+ former r1 is at resvec_saved_area + 8
+ former tr0 is at resvec_saved_area + 32
+ DCR is the only register whose value is lost altogether.
+ */
+
+ movi 0xffffffff80000000, r0 ! phy of dump area
+ ld.q SP, 0x000, r1 ! former r0
+ st.q r0, 0x000, r1
+ ld.q SP, 0x008, r1 ! former r1
+ st.q r0, 0x008, r1
+ st.q r0, 0x010, r2
+ st.q r0, 0x018, r3
+ st.q r0, 0x020, r4
+ st.q r0, 0x028, r5
+ st.q r0, 0x030, r6
+ st.q r0, 0x038, r7
+ st.q r0, 0x040, r8
+ st.q r0, 0x048, r9
+ st.q r0, 0x050, r10
+ st.q r0, 0x058, r11
+ st.q r0, 0x060, r12
+ st.q r0, 0x068, r13
+ st.q r0, 0x070, r14
+ getcon dcr, r14
+ st.q r0, 0x078, r14
+ st.q r0, 0x080, r16
+ st.q r0, 0x088, r17
+ st.q r0, 0x090, r18
+ st.q r0, 0x098, r19
+ st.q r0, 0x0a0, r20
+ st.q r0, 0x0a8, r21
+ st.q r0, 0x0b0, r22
+ st.q r0, 0x0b8, r23
+ st.q r0, 0x0c0, r24
+ st.q r0, 0x0c8, r25
+ st.q r0, 0x0d0, r26
+ st.q r0, 0x0d8, r27
+ st.q r0, 0x0e0, r28
+ st.q r0, 0x0e8, r29
+ st.q r0, 0x0f0, r30
+ st.q r0, 0x0f8, r31
+ st.q r0, 0x100, r32
+ st.q r0, 0x108, r33
+ st.q r0, 0x110, r34
+ st.q r0, 0x118, r35
+ st.q r0, 0x120, r36
+ st.q r0, 0x128, r37
+ st.q r0, 0x130, r38
+ st.q r0, 0x138, r39
+ st.q r0, 0x140, r40
+ st.q r0, 0x148, r41
+ st.q r0, 0x150, r42
+ st.q r0, 0x158, r43
+ st.q r0, 0x160, r44
+ st.q r0, 0x168, r45
+ st.q r0, 0x170, r46
+ st.q r0, 0x178, r47
+ st.q r0, 0x180, r48
+ st.q r0, 0x188, r49
+ st.q r0, 0x190, r50
+ st.q r0, 0x198, r51
+ st.q r0, 0x1a0, r52
+ st.q r0, 0x1a8, r53
+ st.q r0, 0x1b0, r54
+ st.q r0, 0x1b8, r55
+ st.q r0, 0x1c0, r56
+ st.q r0, 0x1c8, r57
+ st.q r0, 0x1d0, r58
+ st.q r0, 0x1d8, r59
+ st.q r0, 0x1e0, r60
+ st.q r0, 0x1e8, r61
+ st.q r0, 0x1f0, r62
+ st.q r0, 0x1f8, r63 ! bogus, but for consistency's sake...
+
+ ld.q SP, 0x020, r1 ! former tr0
+ st.q r0, 0x200, r1
+ gettr tr1, r1
+ st.q r0, 0x208, r1
+ gettr tr2, r1
+ st.q r0, 0x210, r1
+ gettr tr3, r1
+ st.q r0, 0x218, r1
+ gettr tr4, r1
+ st.q r0, 0x220, r1
+ gettr tr5, r1
+ st.q r0, 0x228, r1
+ gettr tr6, r1
+ st.q r0, 0x230, r1
+ gettr tr7, r1
+ st.q r0, 0x238, r1
+
+ getcon sr, r1
+ getcon ssr, r2
+ getcon pssr, r3
+ getcon spc, r4
+ getcon pspc, r5
+ getcon intevt, r6
+ getcon expevt, r7
+ getcon pexpevt, r8
+ getcon tra, r9
+ getcon tea, r10
+ getcon kcr0, r11
+ getcon kcr1, r12
+ getcon vbr, r13
+ getcon resvec, r14
+
+ st.q r0, 0x240, r1
+ st.q r0, 0x248, r2
+ st.q r0, 0x250, r3
+ st.q r0, 0x258, r4
+ st.q r0, 0x260, r5
+ st.q r0, 0x268, r6
+ st.q r0, 0x270, r7
+ st.q r0, 0x278, r8
+ st.q r0, 0x280, r9
+ st.q r0, 0x288, r10
+ st.q r0, 0x290, r11
+ st.q r0, 0x298, r12
+ st.q r0, 0x2a0, r13
+ st.q r0, 0x2a8, r14
+
+ getcon SPC,r2
+ getcon SSR,r3
+ getcon EXPEVT,r4
+ /* Prepare to jump to C - physical address */
+ movi panic_handler-CONFIG_PAGE_OFFSET, r1
+ ori r1, 1, r1
+ ptabs r1, tr0
+ getcon DCR, SP
+ blink tr0, ZERO
+ nop
+ nop
+ nop
+ nop
+
+
+
+
+/*
+ * --- Signal Handling Section
+ */
+
+/*
+ * extern long long _sa_default_rt_restorer
+ * extern long long _sa_default_restorer
+ *
+ * or, better,
+ *
+ * extern void _sa_default_rt_restorer(void)
+ * extern void _sa_default_restorer(void)
+ *
+ * Code prototypes to do a sys_rt_sigreturn() or sys_sysreturn()
+ * from user space. Copied into user space by signal management.
+ * Both must be quad aligned and 2 quad long (4 instructions).
+ *
+ */
+ .balign 8
+ .global sa_default_rt_restorer
+sa_default_rt_restorer:
+ movi 0x10, r9
+ shori __NR_rt_sigreturn, r9
+ trapa r9
+ nop
+
+ .balign 8
+ .global sa_default_restorer
+sa_default_restorer:
+ movi 0x10, r9
+ shori __NR_sigreturn, r9
+ trapa r9
+ nop
+
+/*
+ * --- __ex_table Section
+ */
+
+/*
+ * User Access Exception Table.
+ */
+ .section __ex_table, "a"
+
+ .global asm_uaccess_start /* Just a marker */
+asm_uaccess_start:
+
+ .long ___copy_user1, ___copy_user_exit
+ .long ___copy_user2, ___copy_user_exit
+ .long ___clear_user1, ___clear_user_exit
+ .long ___strncpy_from_user1, ___strncpy_from_user_exit
+ .long ___strnlen_user1, ___strnlen_user_exit
+ .long ___get_user_asm_b1, ___get_user_asm_b_exit
+ .long ___get_user_asm_w1, ___get_user_asm_w_exit
+ .long ___get_user_asm_l1, ___get_user_asm_l_exit
+ .long ___get_user_asm_q1, ___get_user_asm_q_exit
+ .long ___put_user_asm_b1, ___put_user_asm_b_exit
+ .long ___put_user_asm_w1, ___put_user_asm_w_exit
+ .long ___put_user_asm_l1, ___put_user_asm_l_exit
+ .long ___put_user_asm_q1, ___put_user_asm_q_exit
+
+ .global asm_uaccess_end /* Just a marker */
+asm_uaccess_end:
+
+
+
+
+/*
+ * --- .text.init Section
+ */
+
+ .section .text.init, "ax"
+
+/*
+ * void trap_init (void)
+ *
+ */
+ .global trap_init
+trap_init:
+ addi SP, -24, SP /* Room to save r28/r29/r30 */
+ st.q SP, 0, r28
+ st.q SP, 8, r29
+ st.q SP, 16, r30
+
+ /* Set VBR and RESVEC */
+ movi LVBR_block, r19
+ andi r19, -4, r19 /* reset MMUOFF + reserved */
+ /* For RESVEC exceptions we force the MMU off, which means we need the
+ physical address. */
+ movi LRESVEC_block-CONFIG_PAGE_OFFSET, r20
+ andi r20, -4, r20 /* reset reserved */
+ ori r20, 1, r20 /* set MMUOFF */
+ putcon r19, VBR
+ putcon r20, RESVEC
+
+ /* Sanity check */
+ movi LVBR_block_end, r21
+ andi r21, -4, r21
+ movi BLOCK_SIZE, r29 /* r29 = expected size */
+ or r19, ZERO, r30
+ add r19, r29, r19
+
+ /*
+ * Ugly, but better loop forever now than crash afterwards.
+ * We should print a message, but if we touch LVBR or
+ * LRESVEC blocks we should not be surprised if we get stuck
+ * in trap_init().
+ */
+ pta trap_init_loop, tr1
+ gettr tr1, r28 /* r28 = trap_init_loop */
+ sub r21, r30, r30 /* r30 = actual size */
+
+ /*
+ * VBR/RESVEC handlers overlap by being bigger than
+ * allowed. Very bad. Just loop forever.
+ * (r28) panic/loop address
+ * (r29) expected size
+ * (r30) actual size
+ */
+trap_init_loop:
+ bne r19, r21, tr1
+
+ /* Now that exception vectors are set up reset SR.BL */
+ getcon SR, r22
+ movi SR_UNBLOCK_EXC, r23
+ and r22, r23, r22
+ putcon r22, SR
+
+ addi SP, 24, SP
+ ptabs LINK, tr0
+ blink tr0, ZERO
+
diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c
new file mode 100644
index 000000000000..30b76a94abf2
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/fpu.c
@@ -0,0 +1,166 @@
+/*
+ * arch/sh/kernel/cpu/sh5/fpu.c
+ *
+ * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli
+ * Copyright (C) 2002 STMicroelectronics Limited
+ * Author : Stuart Menefy
+ *
+ * Started from SH4 version:
+ * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/processor.h>
+#include <asm/user.h>
+#include <asm/io.h>
+
+/*
+ * Initially load the FPU with signalling NANS. This bit pattern
+ * has the property that no matter whether considered as single or as
+ * double precision, it still represents a signalling NAN.
+ */
+#define sNAN64 0xFFFFFFFFFFFFFFFFULL
+#define sNAN32 0xFFFFFFFFUL
+
+static union sh_fpu_union init_fpuregs = {
+ .hard = {
+ .fp_regs = { [0 ... 63] = sNAN32 },
+ .fpscr = FPSCR_INIT
+ }
+};
+
+void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+ asm volatile("fst.p %0, (0*8), fp0\n\t"
+ "fst.p %0, (1*8), fp2\n\t"
+ "fst.p %0, (2*8), fp4\n\t"
+ "fst.p %0, (3*8), fp6\n\t"
+ "fst.p %0, (4*8), fp8\n\t"
+ "fst.p %0, (5*8), fp10\n\t"
+ "fst.p %0, (6*8), fp12\n\t"
+ "fst.p %0, (7*8), fp14\n\t"
+ "fst.p %0, (8*8), fp16\n\t"
+ "fst.p %0, (9*8), fp18\n\t"
+ "fst.p %0, (10*8), fp20\n\t"
+ "fst.p %0, (11*8), fp22\n\t"
+ "fst.p %0, (12*8), fp24\n\t"
+ "fst.p %0, (13*8), fp26\n\t"
+ "fst.p %0, (14*8), fp28\n\t"
+ "fst.p %0, (15*8), fp30\n\t"
+ "fst.p %0, (16*8), fp32\n\t"
+ "fst.p %0, (17*8), fp34\n\t"
+ "fst.p %0, (18*8), fp36\n\t"
+ "fst.p %0, (19*8), fp38\n\t"
+ "fst.p %0, (20*8), fp40\n\t"
+ "fst.p %0, (21*8), fp42\n\t"
+ "fst.p %0, (22*8), fp44\n\t"
+ "fst.p %0, (23*8), fp46\n\t"
+ "fst.p %0, (24*8), fp48\n\t"
+ "fst.p %0, (25*8), fp50\n\t"
+ "fst.p %0, (26*8), fp52\n\t"
+ "fst.p %0, (27*8), fp54\n\t"
+ "fst.p %0, (28*8), fp56\n\t"
+ "fst.p %0, (29*8), fp58\n\t"
+ "fst.p %0, (30*8), fp60\n\t"
+ "fst.p %0, (31*8), fp62\n\t"
+
+ "fgetscr fr63\n\t"
+ "fst.s %0, (32*8), fr63\n\t"
+ : /* no output */
+ : "r" (&tsk->thread.fpu.hard)
+ : "memory");
+}
+
+static inline void
+fpload(struct sh_fpu_hard_struct *fpregs)
+{
+ asm volatile("fld.p %0, (0*8), fp0\n\t"
+ "fld.p %0, (1*8), fp2\n\t"
+ "fld.p %0, (2*8), fp4\n\t"
+ "fld.p %0, (3*8), fp6\n\t"
+ "fld.p %0, (4*8), fp8\n\t"
+ "fld.p %0, (5*8), fp10\n\t"
+ "fld.p %0, (6*8), fp12\n\t"
+ "fld.p %0, (7*8), fp14\n\t"
+ "fld.p %0, (8*8), fp16\n\t"
+ "fld.p %0, (9*8), fp18\n\t"
+ "fld.p %0, (10*8), fp20\n\t"
+ "fld.p %0, (11*8), fp22\n\t"
+ "fld.p %0, (12*8), fp24\n\t"
+ "fld.p %0, (13*8), fp26\n\t"
+ "fld.p %0, (14*8), fp28\n\t"
+ "fld.p %0, (15*8), fp30\n\t"
+ "fld.p %0, (16*8), fp32\n\t"
+ "fld.p %0, (17*8), fp34\n\t"
+ "fld.p %0, (18*8), fp36\n\t"
+ "fld.p %0, (19*8), fp38\n\t"
+ "fld.p %0, (20*8), fp40\n\t"
+ "fld.p %0, (21*8), fp42\n\t"
+ "fld.p %0, (22*8), fp44\n\t"
+ "fld.p %0, (23*8), fp46\n\t"
+ "fld.p %0, (24*8), fp48\n\t"
+ "fld.p %0, (25*8), fp50\n\t"
+ "fld.p %0, (26*8), fp52\n\t"
+ "fld.p %0, (27*8), fp54\n\t"
+ "fld.p %0, (28*8), fp56\n\t"
+ "fld.p %0, (29*8), fp58\n\t"
+ "fld.p %0, (30*8), fp60\n\t"
+
+ "fld.s %0, (32*8), fr63\n\t"
+ "fputscr fr63\n\t"
+
+ "fld.p %0, (31*8), fp62\n\t"
+ : /* no output */
+ : "r" (fpregs) );
+}
+
+void fpinit(struct sh_fpu_hard_struct *fpregs)
+{
+ *fpregs = init_fpuregs.hard;
+}
+
+asmlinkage void
+do_fpu_error(unsigned long ex, struct pt_regs *regs)
+{
+ struct task_struct *tsk = current;
+
+ regs->pc += 4;
+
+ tsk->thread.trap_no = 11;
+ tsk->thread.error_code = 0;
+ force_sig(SIGFPE, tsk);
+}
+
+
+asmlinkage void
+do_fpu_state_restore(unsigned long ex, struct pt_regs *regs)
+{
+ void die(const char *str, struct pt_regs *regs, long err);
+
+ if (! user_mode(regs))
+ die("FPU used in kernel", regs, ex);
+
+ regs->sr &= ~SR_FD;
+
+ if (last_task_used_math == current)
+ return;
+
+ enable_fpu();
+ if (last_task_used_math != NULL)
+ /* Other processes fpu state, save away */
+ save_fpu(last_task_used_math, regs);
+
+ last_task_used_math = current;
+ if (used_math()) {
+ fpload(&current->thread.fpu.hard);
+ } else {
+ /* First time FPU user. */
+ fpload(&init_fpuregs.hard);
+ set_used_math();
+ }
+ disable_fpu();
+}
diff --git a/arch/sh/kernel/cpu/sh5/probe.c b/arch/sh/kernel/cpu/sh5/probe.c
new file mode 100644
index 000000000000..15d167fd0ae7
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/probe.c
@@ -0,0 +1,76 @@
+/*
+ * arch/sh/kernel/cpu/sh5/probe.c
+ *
+ * CPU Subtype Probing for SH-5.
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+ unsigned long long cir;
+
+ /* Do peeks in real mode to avoid having to set up a mapping for the
+ WPC registers. On SH5-101 cut2, such a mapping would be exposed to
+ an address translation erratum which would make it hard to set up
+ correctly. */
+ cir = peek_real_address_q(0x0d000008);
+ if ((cir & 0xffff) == 0x5103) {
+ boot_cpu_data.type = CPU_SH5_103;
+ } else if (((cir >> 32) & 0xffff) == 0x51e2) {
+ /* CPU.VCR aliased at CIR address on SH5-101 */
+ boot_cpu_data.type = CPU_SH5_101;
+ } else {
+ boot_cpu_data.type = CPU_SH_NONE;
+ }
+
+ /*
+ * First, setup some sane values for the I-cache.
+ */
+ boot_cpu_data.icache.ways = 4;
+ boot_cpu_data.icache.sets = 256;
+ boot_cpu_data.icache.linesz = L1_CACHE_BYTES;
+
+#if 0
+ /*
+ * FIXME: This can probably be cleaned up a bit as well.. for example,
+ * do we really need the way shift _and_ the way_step_shift ?? Judging
+ * by the existing code, I would guess no.. is there any valid reason
+ * why we need to be tracking this around?
+ */
+ boot_cpu_data.icache.way_shift = 13;
+ boot_cpu_data.icache.entry_shift = 5;
+ boot_cpu_data.icache.set_shift = 4;
+ boot_cpu_data.icache.way_step_shift = 16;
+ boot_cpu_data.icache.asid_shift = 2;
+
+ /*
+ * way offset = cache size / associativity, so just don't factor in
+ * associativity in the first place..
+ */
+ boot_cpu_data.icache.way_ofs = boot_cpu_data.icache.sets *
+ boot_cpu_data.icache.linesz;
+
+ boot_cpu_data.icache.asid_mask = 0x3fc;
+ boot_cpu_data.icache.idx_mask = 0x1fe0;
+ boot_cpu_data.icache.epn_mask = 0xffffe000;
+#endif
+
+ boot_cpu_data.icache.flags = 0;
+
+ /* A trivial starting point.. */
+ memcpy(&boot_cpu_data.dcache,
+ &boot_cpu_data.icache, sizeof(struct cache_info));
+
+ return 0;
+}
diff --git a/arch/sh/kernel/cpu/sh5/switchto.S b/arch/sh/kernel/cpu/sh5/switchto.S
new file mode 100644
index 000000000000..45c351b0f1ba
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/switchto.S
@@ -0,0 +1,198 @@
+/*
+ * arch/sh/kernel/cpu/sh5/switchto.S
+ *
+ * sh64 context switch
+ *
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+*/
+
+ .section .text..SHmedia32,"ax"
+ .little
+
+ .balign 32
+
+ .type sh64_switch_to,@function
+ .global sh64_switch_to
+ .global __sh64_switch_to_end
+sh64_switch_to:
+
+/* Incoming args
+ r2 - prev
+ r3 - &prev->thread
+ r4 - next
+ r5 - &next->thread
+
+ Outgoing results
+ r2 - last (=prev) : this just stays in r2 throughout
+
+ Want to create a full (struct pt_regs) on the stack to allow backtracing
+ functions to work. However, we only need to populate the callee-save
+ register slots in this structure; since we're a function our ancestors must
+ have themselves preserved all caller saved state in the stack. This saves
+ some wasted effort since we won't need to look at the values.
+
+ In particular, all caller-save registers are immediately available for
+ scratch use.
+
+*/
+
+#define FRAME_SIZE (76*8 + 8)
+
+ movi FRAME_SIZE, r0
+ sub.l r15, r0, r15
+ ! Do normal-style register save to support backtrace
+
+ st.l r15, 0, r18 ! save link reg
+ st.l r15, 4, r14 ! save fp
+ add.l r15, r63, r14 ! setup frame pointer
+
+ ! hopefully this looks normal to the backtrace now.
+
+ addi.l r15, 8, r1 ! base of pt_regs
+ addi.l r1, 24, r0 ! base of pt_regs.regs
+ addi.l r0, (63*8), r8 ! base of pt_regs.trregs
+
+ /* Note : to be fixed?
+ struct pt_regs is really designed for holding the state on entry
+ to an exception, i.e. pc,sr,regs etc. However, for the context
+ switch state, some of this is not required. But the unwinder takes
+ struct pt_regs * as an arg so we have to build this structure
+ to allow unwinding switched tasks in show_state() */
+
+ st.q r0, ( 9*8), r9
+ st.q r0, (10*8), r10
+ st.q r0, (11*8), r11
+ st.q r0, (12*8), r12
+ st.q r0, (13*8), r13
+ st.q r0, (14*8), r14 ! for unwind, want to look as though we took a trap at
+ ! the point where the process is left in suspended animation, i.e. current
+ ! fp here, not the saved one.
+ st.q r0, (16*8), r16
+
+ st.q r0, (24*8), r24
+ st.q r0, (25*8), r25
+ st.q r0, (26*8), r26
+ st.q r0, (27*8), r27
+ st.q r0, (28*8), r28
+ st.q r0, (29*8), r29
+ st.q r0, (30*8), r30
+ st.q r0, (31*8), r31
+ st.q r0, (32*8), r32
+ st.q r0, (33*8), r33
+ st.q r0, (34*8), r34
+ st.q r0, (35*8), r35
+
+ st.q r0, (44*8), r44
+ st.q r0, (45*8), r45
+ st.q r0, (46*8), r46
+ st.q r0, (47*8), r47
+ st.q r0, (48*8), r48
+ st.q r0, (49*8), r49
+ st.q r0, (50*8), r50
+ st.q r0, (51*8), r51
+ st.q r0, (52*8), r52
+ st.q r0, (53*8), r53
+ st.q r0, (54*8), r54
+ st.q r0, (55*8), r55
+ st.q r0, (56*8), r56
+ st.q r0, (57*8), r57
+ st.q r0, (58*8), r58
+ st.q r0, (59*8), r59
+
+ ! do this early as pta->gettr has no pipeline forwarding (=> 5 cycle latency)
+ ! Use a local label to avoid creating a symbol that will confuse the !
+ ! backtrace
+ pta .Lsave_pc, tr0
+
+ gettr tr5, r45
+ gettr tr6, r46
+ gettr tr7, r47
+ st.q r8, (5*8), r45
+ st.q r8, (6*8), r46
+ st.q r8, (7*8), r47
+
+ ! Now switch context
+ gettr tr0, r9
+ st.l r3, 0, r15 ! prev->thread.sp
+ st.l r3, 8, r1 ! prev->thread.kregs
+ st.l r3, 4, r9 ! prev->thread.pc
+ st.q r1, 0, r9 ! save prev->thread.pc into pt_regs->pc
+
+ ! Load PC for next task (init value or save_pc later)
+ ld.l r5, 4, r18 ! next->thread.pc
+ ! Switch stacks
+ ld.l r5, 0, r15 ! next->thread.sp
+ ptabs r18, tr0
+
+ ! Update current
+ ld.l r4, 4, r9 ! next->thread_info (2nd element of next task_struct)
+ putcon r9, kcr0 ! current = next->thread_info
+
+ ! go to save_pc for a reschedule, or the initial thread.pc for a new process
+ blink tr0, r63
+
+ ! Restore (when we come back to a previously saved task)
+.Lsave_pc:
+ addi.l r15, 32, r0 ! r0 = next's regs
+ addi.l r0, (63*8), r8 ! r8 = next's tr_regs
+
+ ld.q r8, (5*8), r45
+ ld.q r8, (6*8), r46
+ ld.q r8, (7*8), r47
+ ptabs r45, tr5
+ ptabs r46, tr6
+ ptabs r47, tr7
+
+ ld.q r0, ( 9*8), r9
+ ld.q r0, (10*8), r10
+ ld.q r0, (11*8), r11
+ ld.q r0, (12*8), r12
+ ld.q r0, (13*8), r13
+ ld.q r0, (14*8), r14
+ ld.q r0, (16*8), r16
+
+ ld.q r0, (24*8), r24
+ ld.q r0, (25*8), r25
+ ld.q r0, (26*8), r26
+ ld.q r0, (27*8), r27
+ ld.q r0, (28*8), r28
+ ld.q r0, (29*8), r29
+ ld.q r0, (30*8), r30
+ ld.q r0, (31*8), r31
+ ld.q r0, (32*8), r32
+ ld.q r0, (33*8), r33
+ ld.q r0, (34*8), r34
+ ld.q r0, (35*8), r35
+
+ ld.q r0, (44*8), r44
+ ld.q r0, (45*8), r45
+ ld.q r0, (46*8), r46
+ ld.q r0, (47*8), r47
+ ld.q r0, (48*8), r48
+ ld.q r0, (49*8), r49
+ ld.q r0, (50*8), r50
+ ld.q r0, (51*8), r51
+ ld.q r0, (52*8), r52
+ ld.q r0, (53*8), r53
+ ld.q r0, (54*8), r54
+ ld.q r0, (55*8), r55
+ ld.q r0, (56*8), r56
+ ld.q r0, (57*8), r57
+ ld.q r0, (58*8), r58
+ ld.q r0, (59*8), r59
+
+ ! epilogue
+ ld.l r15, 0, r18
+ ld.l r15, 4, r14
+ ptabs r18, tr0
+ movi FRAME_SIZE, r0
+ add r15, r0, r15
+ blink tr0, r63
+__sh64_switch_to_end:
+.LFE1:
+ .size sh64_switch_to,.LFE1-sh64_switch_to
+
diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c
new file mode 100644
index 000000000000..119c20afd4e5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/unwind.c
@@ -0,0 +1,326 @@
+/*
+ * arch/sh/kernel/cpu/sh5/unwind.c
+ *
+ * Copyright (C) 2004 Paul Mundt
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+static u8 regcache[63];
+
+/*
+ * Finding the previous stack frame isn't horribly straightforward as it is
+ * on some other platforms. In the sh64 case, we don't have "linked" stack
+ * frames, so we need to do a bit of work to determine the previous frame,
+ * and in turn, the previous r14/r18 pair.
+ *
+ * There are generally a few cases which determine where we can find out
+ * the r14/r18 values. In the general case, this can be determined by poking
+ * around the prologue of the symbol PC is in (note that we absolutely must
+ * have frame pointer support as well as the kernel symbol table mapped,
+ * otherwise we can't even get this far).
+ *
+ * In other cases, such as the interrupt/exception path, we can poke around
+ * the sp/fp.
+ *
+ * Notably, this entire approach is somewhat error prone, and in the event
+ * that the previous frame cannot be determined, that's all we can do.
+ * Either way, this still leaves us with a more correct backtrace then what
+ * we would be able to come up with by walking the stack (which is garbage
+ * for anything beyond the first frame).
+ * -- PFM.
+ */
+static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
+ unsigned long *pprev_fp, unsigned long *pprev_pc,
+ struct pt_regs *regs)
+{
+ const char *sym;
+ char namebuf[128];
+ unsigned long offset;
+ unsigned long prologue = 0;
+ unsigned long fp_displacement = 0;
+ unsigned long fp_prev = 0;
+ unsigned long offset_r14 = 0, offset_r18 = 0;
+ int i, found_prologue_end = 0;
+
+ sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf);
+ if (!sym)
+ return -EINVAL;
+
+ prologue = pc - offset;
+ if (!prologue)
+ return -EINVAL;
+
+ /* Validate fp, to avoid risk of dereferencing a bad pointer later.
+ Assume 128Mb since that's the amount of RAM on a Cayman. Modify
+ when there is an SH-5 board with more. */
+ if ((fp < (unsigned long) phys_to_virt(__MEMORY_START)) ||
+ (fp >= (unsigned long)(phys_to_virt(__MEMORY_START)) + 128*1024*1024) ||
+ ((fp & 7) != 0)) {
+ return -EINVAL;
+ }
+
+ /*
+ * Depth to walk, depth is completely arbitrary.
+ */
+ for (i = 0; i < 100; i++, prologue += sizeof(unsigned long)) {
+ unsigned long op;
+ u8 major, minor;
+ u8 src, dest, disp;
+
+ op = *(unsigned long *)prologue;
+
+ major = (op >> 26) & 0x3f;
+ src = (op >> 20) & 0x3f;
+ minor = (op >> 16) & 0xf;
+ disp = (op >> 10) & 0x3f;
+ dest = (op >> 4) & 0x3f;
+
+ /*
+ * Stack frame creation happens in a number of ways.. in the
+ * general case when the stack frame is less than 511 bytes,
+ * it's generally created by an addi or addi.l:
+ *
+ * addi/addi.l r15, -FRAME_SIZE, r15
+ *
+ * in the event that the frame size is bigger than this, it's
+ * typically created using a movi/sub pair as follows:
+ *
+ * movi FRAME_SIZE, rX
+ * sub r15, rX, r15
+ */
+
+ switch (major) {
+ case (0x00 >> 2):
+ switch (minor) {
+ case 0x8: /* add.l */
+ case 0x9: /* add */
+ /* Look for r15, r63, r14 */
+ if (src == 15 && disp == 63 && dest == 14)
+ found_prologue_end = 1;
+
+ break;
+ case 0xa: /* sub.l */
+ case 0xb: /* sub */
+ if (src != 15 || dest != 15)
+ continue;
+
+ fp_displacement -= regcache[disp];
+ fp_prev = fp - fp_displacement;
+ break;
+ }
+ break;
+ case (0xa8 >> 2): /* st.l */
+ if (src != 15)
+ continue;
+
+ switch (dest) {
+ case 14:
+ if (offset_r14 || fp_displacement == 0)
+ continue;
+
+ offset_r14 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+ offset_r14 *= sizeof(unsigned long);
+ offset_r14 += fp_displacement;
+ break;
+ case 18:
+ if (offset_r18 || fp_displacement == 0)
+ continue;
+
+ offset_r18 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+ offset_r18 *= sizeof(unsigned long);
+ offset_r18 += fp_displacement;
+ break;
+ }
+
+ break;
+ case (0xcc >> 2): /* movi */
+ if (dest >= 63) {
+ printk(KERN_NOTICE "%s: Invalid dest reg %d "
+ "specified in movi handler. Failed "
+ "opcode was 0x%lx: ", __FUNCTION__,
+ dest, op);
+
+ continue;
+ }
+
+ /* Sign extend */
+ regcache[dest] =
+ ((((s64)(u64)op >> 10) & 0xffff) << 54) >> 54;
+ break;
+ case (0xd0 >> 2): /* addi */
+ case (0xd4 >> 2): /* addi.l */
+ /* Look for r15, -FRAME_SIZE, r15 */
+ if (src != 15 || dest != 15)
+ continue;
+
+ /* Sign extended frame size.. */
+ fp_displacement +=
+ (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+ fp_prev = fp - fp_displacement;
+ break;
+ }
+
+ if (found_prologue_end && offset_r14 && (offset_r18 || *pprev_pc) && fp_prev)
+ break;
+ }
+
+ if (offset_r14 == 0 || fp_prev == 0) {
+ if (!offset_r14)
+ pr_debug("Unable to find r14 offset\n");
+ if (!fp_prev)
+ pr_debug("Unable to find previous fp\n");
+
+ return -EINVAL;
+ }
+
+ /* For innermost leaf function, there might not be a offset_r18 */
+ if (!*pprev_pc && (offset_r18 == 0))
+ return -EINVAL;
+
+ *pprev_fp = *(unsigned long *)(fp_prev + offset_r14);
+
+ if (offset_r18)
+ *pprev_pc = *(unsigned long *)(fp_prev + offset_r18);
+
+ *pprev_pc &= ~1;
+
+ return 0;
+}
+
+/* Don't put this on the stack since we'll want to call sh64_unwind
+ * when we're close to underflowing the stack anyway. */
+static struct pt_regs here_regs;
+
+extern const char syscall_ret;
+extern const char ret_from_syscall;
+extern const char ret_from_exception;
+extern const char ret_from_irq;
+
+static void sh64_unwind_inner(struct pt_regs *regs);
+
+static void unwind_nested (unsigned long pc, unsigned long fp)
+{
+ if ((fp >= __MEMORY_START) &&
+ ((fp & 7) == 0)) {
+ sh64_unwind_inner((struct pt_regs *) fp);
+ }
+}
+
+static void sh64_unwind_inner(struct pt_regs *regs)
+{
+ unsigned long pc, fp;
+ int ofs = 0;
+ int first_pass;
+
+ pc = regs->pc & ~1;
+ fp = regs->regs[14];
+
+ first_pass = 1;
+ for (;;) {
+ int cond;
+ unsigned long next_fp, next_pc;
+
+ if (pc == ((unsigned long) &syscall_ret & ~1)) {
+ printk("SYSCALL\n");
+ unwind_nested(pc,fp);
+ return;
+ }
+
+ if (pc == ((unsigned long) &ret_from_syscall & ~1)) {
+ printk("SYSCALL (PREEMPTED)\n");
+ unwind_nested(pc,fp);
+ return;
+ }
+
+ /* In this case, the PC is discovered by lookup_prev_stack_frame but
+ it has 4 taken off it to look like the 'caller' */
+ if (pc == ((unsigned long) &ret_from_exception & ~1)) {
+ printk("EXCEPTION\n");
+ unwind_nested(pc,fp);
+ return;
+ }
+
+ if (pc == ((unsigned long) &ret_from_irq & ~1)) {
+ printk("IRQ\n");
+ unwind_nested(pc,fp);
+ return;
+ }
+
+ cond = ((pc >= __MEMORY_START) && (fp >= __MEMORY_START) &&
+ ((pc & 3) == 0) && ((fp & 7) == 0));
+
+ pc -= ofs;
+
+ printk("[<%08lx>] ", pc);
+ print_symbol("%s\n", pc);
+
+ if (first_pass) {
+ /* If the innermost frame is a leaf function, it's
+ * possible that r18 is never saved out to the stack.
+ */
+ next_pc = regs->regs[18];
+ } else {
+ next_pc = 0;
+ }
+
+ if (lookup_prev_stack_frame(fp, pc, &next_fp, &next_pc, regs) == 0) {
+ ofs = sizeof(unsigned long);
+ pc = next_pc & ~1;
+ fp = next_fp;
+ } else {
+ printk("Unable to lookup previous stack frame\n");
+ break;
+ }
+ first_pass = 0;
+ }
+
+ printk("\n");
+
+}
+
+void sh64_unwind(struct pt_regs *regs)
+{
+ if (!regs) {
+ /*
+ * Fetch current regs if we have no other saved state to back
+ * trace from.
+ */
+ regs = &here_regs;
+
+ __asm__ __volatile__ ("ori r14, 0, %0" : "=r" (regs->regs[14]));
+ __asm__ __volatile__ ("ori r15, 0, %0" : "=r" (regs->regs[15]));
+ __asm__ __volatile__ ("ori r18, 0, %0" : "=r" (regs->regs[18]));
+
+ __asm__ __volatile__ ("gettr tr0, %0" : "=r" (regs->tregs[0]));
+ __asm__ __volatile__ ("gettr tr1, %0" : "=r" (regs->tregs[1]));
+ __asm__ __volatile__ ("gettr tr2, %0" : "=r" (regs->tregs[2]));
+ __asm__ __volatile__ ("gettr tr3, %0" : "=r" (regs->tregs[3]));
+ __asm__ __volatile__ ("gettr tr4, %0" : "=r" (regs->tregs[4]));
+ __asm__ __volatile__ ("gettr tr5, %0" : "=r" (regs->tregs[5]));
+ __asm__ __volatile__ ("gettr tr6, %0" : "=r" (regs->tregs[6]));
+ __asm__ __volatile__ ("gettr tr7, %0" : "=r" (regs->tregs[7]));
+
+ __asm__ __volatile__ (
+ "pta 0f, tr0\n\t"
+ "blink tr0, %0\n\t"
+ "0: nop"
+ : "=r" (regs->pc)
+ );
+ }
+
+ printk("\nCall Trace:\n");
+ sh64_unwind_inner(regs);
+}
+
diff --git a/arch/sh/kernel/dump_task.c b/arch/sh/kernel/dump_task.c
new file mode 100644
index 000000000000..4a8a4083ff0b
--- /dev/null
+++ b/arch/sh/kernel/dump_task.c
@@ -0,0 +1,31 @@
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+
+/*
+ * Capture the user space registers if the task is not running (in user space)
+ */
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+ struct pt_regs ptregs;
+
+ ptregs = *task_pt_regs(tsk);
+ elf_core_copy_regs(regs, &ptregs);
+
+ return 1;
+}
+
+int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
+{
+ int fpvalid = 0;
+
+#if defined(CONFIG_SH_FPU)
+ fpvalid = !!tsk_used_math(tsk);
+ if (fpvalid) {
+ unlazy_fpu(tsk, task_pt_regs(tsk));
+ memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+ }
+#endif
+
+ return fpvalid;
+}
+
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 2f30977558ad..957f25611543 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -63,7 +63,8 @@ static struct console bios_console = {
#include <linux/serial_core.h>
#include "../../../drivers/serial/sh-sci.h"
-#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721)
#define EPK_SCSMR_VALUE 0x000
#define EPK_SCBRR_VALUE 0x00C
#define EPK_FIFO_SIZE 64
@@ -117,7 +118,8 @@ static struct console scif_console = {
};
#if !defined(CONFIG_SH_STANDARD_BIOS)
-#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721)
static void scif_sercon_init(char *s)
{
sci_out(&scif_port, SCSCR, 0x0000); /* clear TE and RE */
@@ -208,10 +210,12 @@ static int __init setup_early_printk(char *buf)
if (!strncmp(buf, "serial", 6)) {
early_console = &scif_console;
-#if (defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720)) && \
- !defined(CONFIG_SH_STANDARD_BIOS)
+#if !defined(CONFIG_SH_STANDARD_BIOS)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721)
scif_sercon_init(buf + 6);
#endif
+#endif
}
#endif
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index e0317ed080c3..926b2e7b11c1 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -176,25 +176,6 @@ work_notifysig:
jmp @r1
lds r0, pr
work_resched:
-#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT)
- ! gUSA handling
- mov.l @(OFF_SP,r15), r0 ! get user space stack pointer
- mov r0, r1
- shll r0
- bf/s 1f
- shll r0
- bf/s 1f
- mov #OFF_PC, r0
- ! SP >= 0xc0000000 : gUSA mark
- mov.l @(r0,r15), r2 ! get user space PC (program counter)
- mov.l @(OFF_R0,r15), r3 ! end point
- cmp/hs r3, r2 ! r2 >= r3?
- bt 1f
- add r3, r1 ! rewind point #2
- mov.l r1, @(r0,r15) ! reset PC to rewind point #2
- !
-1:
-#endif
mov.l 1f, r1
jsr @r1 ! schedule
nop
@@ -224,7 +205,7 @@ work_resched:
syscall_exit_work:
! r0: current_thread_info->flags
! r8: current_thread_info
- tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP, r0
+ tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT, r0
bt/s work_pending
tst #_TIF_NEED_RESCHED, r0
#ifdef CONFIG_TRACE_IRQFLAGS
@@ -234,6 +215,8 @@ syscall_exit_work:
#endif
sti
! XXX setup arguments...
+ mov r15, r4
+ mov #1, r5
mov.l 4f, r0 ! do_syscall_trace
jsr @r0
nop
@@ -244,6 +227,8 @@ syscall_exit_work:
syscall_trace_entry:
! Yes it is traced.
! XXX setup arguments...
+ mov r15, r4
+ mov #0, r5
mov.l 4f, r11 ! Call do_syscall_trace which notifies
jsr @r11 ! superior (will chomp R[0-7])
nop
@@ -366,7 +351,7 @@ ENTRY(system_call)
!
get_current_thread_info r8, r10
mov.l @(TI_FLAGS,r8), r8
- mov #_TIF_SYSCALL_TRACE, r10
+ mov #(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT), r10
tst r10, r8
bf syscall_trace_entry
!
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head_32.S
index 3338239717f1..d67d7ed09f22 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head_32.S
@@ -32,7 +32,11 @@ ENTRY(empty_zero_page)
.long 1 /* LOADER_TYPE */
.long 0x00360000 /* INITRD_START */
.long 0x000a0000 /* INITRD_SIZE */
- .long 0
+#ifdef CONFIG_32BIT
+ .long 0x53453f00 + 32 /* "SE?" = 32 bit */
+#else
+ .long 0x53453f00 + 29 /* "SE?" = 29 bit */
+#endif
1:
.skip PAGE_SIZE - empty_zero_page - 1b
diff --git a/arch/sh/kernel/head_64.S b/arch/sh/kernel/head_64.S
new file mode 100644
index 000000000000..f42d4c0feb76
--- /dev/null
+++ b/arch/sh/kernel/head_64.S
@@ -0,0 +1,356 @@
+/*
+ * arch/sh/kernel/head_64.S
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003, 2004 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/tlb.h>
+#include <asm/cpu/registers.h>
+#include <asm/cpu/mmu_context.h>
+#include <asm/thread_info.h>
+
+/*
+ * MMU defines: TLB boundaries.
+ */
+
+#define MMUIR_FIRST ITLB_FIXED
+#define MMUIR_END ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP
+#define MMUIR_STEP TLB_STEP
+
+#define MMUDR_FIRST DTLB_FIXED
+#define MMUDR_END DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP
+#define MMUDR_STEP TLB_STEP
+
+/* Safety check : CONFIG_PAGE_OFFSET has to be a multiple of 512Mb */
+#if (CONFIG_PAGE_OFFSET & ((1UL<<29)-1))
+#error "CONFIG_PAGE_OFFSET must be a multiple of 512Mb"
+#endif
+
+/*
+ * MMU defines: Fixed TLBs.
+ */
+/* Deal safely with the case where the base of RAM is not 512Mb aligned */
+
+#define ALIGN_512M_MASK (0xffffffffe0000000)
+#define ALIGNED_EFFECTIVE ((CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK)
+#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK)
+
+#define MMUIR_TEXT_H (0x0000000000000003 | ALIGNED_EFFECTIVE)
+ /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+
+#define MMUIR_TEXT_L (0x000000000000009a | ALIGNED_PHYSICAL)
+ /* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */
+
+#define MMUDR_CACHED_H 0x0000000000000003 | ALIGNED_EFFECTIVE
+ /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+#define MMUDR_CACHED_L 0x000000000000015a | ALIGNED_PHYSICAL
+ /* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */
+
+#ifdef CONFIG_CACHE_OFF
+#define ICCR0_INIT_VAL ICCR0_OFF /* ICACHE off */
+#else
+#define ICCR0_INIT_VAL ICCR0_ON | ICCR0_ICI /* ICE + ICI */
+#endif
+#define ICCR1_INIT_VAL ICCR1_NOLOCK /* No locking */
+
+#if defined (CONFIG_CACHE_OFF)
+#define OCCR0_INIT_VAL OCCR0_OFF /* D-cache: off */
+#elif defined (CONFIG_CACHE_WRITETHROUGH)
+#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WT /* D-cache: on, */
+ /* WT, invalidate */
+#elif defined (CONFIG_CACHE_WRITEBACK)
+#define OCCR0_INIT_VAL OCCR0_ON | OCCR0_OCI | OCCR0_WB /* D-cache: on, */
+ /* WB, invalidate */
+#else
+#error preprocessor flag CONFIG_CACHE_... not recognized!
+#endif
+
+#define OCCR1_INIT_VAL OCCR1_NOLOCK /* No locking */
+
+ .section .empty_zero_page, "aw"
+ .global empty_zero_page
+
+empty_zero_page:
+ .long 1 /* MOUNT_ROOT_RDONLY */
+ .long 0 /* RAMDISK_FLAGS */
+ .long 0x0200 /* ORIG_ROOT_DEV */
+ .long 1 /* LOADER_TYPE */
+ .long 0x00800000 /* INITRD_START */
+ .long 0x00800000 /* INITRD_SIZE */
+ .long 0
+
+ .text
+ .balign 4096,0,4096
+
+ .section .data, "aw"
+ .balign PAGE_SIZE
+
+ .section .data, "aw"
+ .balign PAGE_SIZE
+
+ .global mmu_pdtp_cache
+mmu_pdtp_cache:
+ .space PAGE_SIZE, 0
+
+ .global empty_bad_page
+empty_bad_page:
+ .space PAGE_SIZE, 0
+
+ .global empty_bad_pte_table
+empty_bad_pte_table:
+ .space PAGE_SIZE, 0
+
+ .global fpu_in_use
+fpu_in_use: .quad 0
+
+
+ .section .text.head, "ax"
+ .balign L1_CACHE_BYTES
+/*
+ * Condition at the entry of __stext:
+ * . Reset state:
+ * . SR.FD = 1 (FPU disabled)
+ * . SR.BL = 1 (Exceptions disabled)
+ * . SR.MD = 1 (Privileged Mode)
+ * . SR.MMU = 0 (MMU Disabled)
+ * . SR.CD = 0 (CTC User Visible)
+ * . SR.IMASK = Undefined (Interrupt Mask)
+ *
+ * Operations supposed to be performed by __stext:
+ * . prevent speculative fetch onto device memory while MMU is off
+ * . reflect as much as possible SH5 ABI (r15, r26, r27, r18)
+ * . first, save CPU state and set it to something harmless
+ * . any CPU detection and/or endianness settings (?)
+ * . initialize EMI/LMI (but not TMU/RTC/INTC/SCIF): TBD
+ * . set initial TLB entries for cached and uncached regions
+ * (no fine granularity paging)
+ * . set initial cache state
+ * . enable MMU and caches
+ * . set CPU to a consistent state
+ * . registers (including stack pointer and current/KCR0)
+ * . NOT expecting to set Exception handling nor VBR/RESVEC/DCR
+ * at this stage. This is all to later Linux initialization steps.
+ * . initialize FPU
+ * . clear BSS
+ * . jump into start_kernel()
+ * . be prepared to hopeless start_kernel() returns.
+ *
+ */
+ .global _stext
+_stext:
+ /*
+ * Prevent speculative fetch on device memory due to
+ * uninitialized target registers.
+ */
+ ptabs/u ZERO, tr0
+ ptabs/u ZERO, tr1
+ ptabs/u ZERO, tr2
+ ptabs/u ZERO, tr3
+ ptabs/u ZERO, tr4
+ ptabs/u ZERO, tr5
+ ptabs/u ZERO, tr6
+ ptabs/u ZERO, tr7
+ synci
+
+ /*
+ * Read/Set CPU state. After this block:
+ * r29 = Initial SR
+ */
+ getcon SR, r29
+ movi SR_HARMLESS, r20
+ putcon r20, SR
+
+ /*
+ * Initialize EMI/LMI. To Be Done.
+ */
+
+ /*
+ * CPU detection and/or endianness settings (?). To Be Done.
+ * Pure PIC code here, please ! Just save state into r30.
+ * After this block:
+ * r30 = CPU type/Platform Endianness
+ */
+
+ /*
+ * Set initial TLB entries for cached and uncached regions.
+ * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
+ */
+ /* Clear ITLBs */
+ pta clear_ITLB, tr1
+ movi MMUIR_FIRST, r21
+ movi MMUIR_END, r22
+clear_ITLB:
+ putcfg r21, 0, ZERO /* Clear MMUIR[n].PTEH.V */
+ addi r21, MMUIR_STEP, r21
+ bne r21, r22, tr1
+
+ /* Clear DTLBs */
+ pta clear_DTLB, tr1
+ movi MMUDR_FIRST, r21
+ movi MMUDR_END, r22
+clear_DTLB:
+ putcfg r21, 0, ZERO /* Clear MMUDR[n].PTEH.V */
+ addi r21, MMUDR_STEP, r21
+ bne r21, r22, tr1
+
+ /* Map one big (512Mb) page for ITLB */
+ movi MMUIR_FIRST, r21
+ movi MMUIR_TEXT_L, r22 /* PTEL first */
+ add.l r22, r63, r22 /* Sign extend */
+ putcfg r21, 1, r22 /* Set MMUIR[0].PTEL */
+ movi MMUIR_TEXT_H, r22 /* PTEH last */
+ add.l r22, r63, r22 /* Sign extend */
+ putcfg r21, 0, r22 /* Set MMUIR[0].PTEH */
+
+ /* Map one big CACHED (512Mb) page for DTLB */
+ movi MMUDR_FIRST, r21
+ movi MMUDR_CACHED_L, r22 /* PTEL first */
+ add.l r22, r63, r22 /* Sign extend */
+ putcfg r21, 1, r22 /* Set MMUDR[0].PTEL */
+ movi MMUDR_CACHED_H, r22 /* PTEH last */
+ add.l r22, r63, r22 /* Sign extend */
+ putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */
+
+#ifdef CONFIG_EARLY_PRINTK
+ /*
+ * Setup a DTLB translation for SCIF phys.
+ */
+ addi r21, MMUDR_STEP, r21
+ movi 0x0a03, r22 /* SCIF phys */
+ shori 0x0148, r22
+ putcfg r21, 1, r22 /* PTEL first */
+ movi 0xfa03, r22 /* 0xfa030000, fixed SCIF virt */
+ shori 0x0003, r22
+ putcfg r21, 0, r22 /* PTEH last */
+#endif
+
+ /*
+ * Set cache behaviours.
+ */
+ /* ICache */
+ movi ICCR_BASE, r21
+ movi ICCR0_INIT_VAL, r22
+ movi ICCR1_INIT_VAL, r23
+ putcfg r21, ICCR_REG0, r22
+ putcfg r21, ICCR_REG1, r23
+
+ /* OCache */
+ movi OCCR_BASE, r21
+ movi OCCR0_INIT_VAL, r22
+ movi OCCR1_INIT_VAL, r23
+ putcfg r21, OCCR_REG0, r22
+ putcfg r21, OCCR_REG1, r23
+
+
+ /*
+ * Enable Caches and MMU. Do the first non-PIC jump.
+ * Now head.S global variables, constants and externs
+ * can be used.
+ */
+ getcon SR, r21
+ movi SR_ENABLE_MMU, r22
+ or r21, r22, r21
+ putcon r21, SSR
+ movi hyperspace, r22
+ ori r22, 1, r22 /* Make it SHmedia, not required but..*/
+ putcon r22, SPC
+ synco
+ rte /* And now go into the hyperspace ... */
+hyperspace: /* ... that's the next instruction ! */
+
+ /*
+ * Set CPU to a consistent state.
+ * r31 = FPU support flag
+ * tr0/tr7 in use. Others give a chance to loop somewhere safe
+ */
+ movi start_kernel, r32
+ ori r32, 1, r32
+
+ ptabs r32, tr0 /* r32 = _start_kernel address */
+ pta/u hopeless, tr1
+ pta/u hopeless, tr2
+ pta/u hopeless, tr3
+ pta/u hopeless, tr4
+ pta/u hopeless, tr5
+ pta/u hopeless, tr6
+ pta/u hopeless, tr7
+ gettr tr1, r28 /* r28 = hopeless address */
+
+ /* Set initial stack pointer */
+ movi init_thread_union, SP
+ putcon SP, KCR0 /* Set current to init_task */
+ movi THREAD_SIZE, r22 /* Point to the end */
+ add SP, r22, SP
+
+ /*
+ * Initialize FPU.
+ * Keep FPU flag in r31. After this block:
+ * r31 = FPU flag
+ */
+ movi fpu_in_use, r31 /* Temporary */
+
+#ifdef CONFIG_SH_FPU
+ getcon SR, r21
+ movi SR_ENABLE_FPU, r22
+ and r21, r22, r22
+ putcon r22, SR /* Try to enable */
+ getcon SR, r22
+ xor r21, r22, r21
+ shlri r21, 15, r21 /* Supposedly 0/1 */
+ st.q r31, 0 , r21 /* Set fpu_in_use */
+#else
+ movi 0, r21
+ st.q r31, 0 , r21 /* Set fpu_in_use */
+#endif
+ or r21, ZERO, r31 /* Set FPU flag at last */
+
+#ifndef CONFIG_SH_NO_BSS_INIT
+/* Don't clear BSS if running on slow platforms such as an RTL simulation,
+ remote memory via SHdebug link, etc. For these the memory can be guaranteed
+ to be all zero on boot anyway. */
+ /*
+ * Clear bss
+ */
+ pta clear_quad, tr1
+ movi __bss_start, r22
+ movi _end, r23
+clear_quad:
+ st.q r22, 0, ZERO
+ addi r22, 8, r22
+ bne r22, r23, tr1 /* Both quad aligned, see vmlinux.lds.S */
+#endif
+ pta/u hopeless, tr1
+
+ /* Say bye to head.S but be prepared to wrongly get back ... */
+ blink tr0, LINK
+
+ /* If we ever get back here through LINK/tr1-tr7 */
+ pta/u hopeless, tr7
+
+hopeless:
+ /*
+ * Something's badly wrong here. Loop endlessly,
+ * there's nothing more we can do about it.
+ *
+ * Note on hopeless: it can be jumped into invariably
+ * before or after jumping into hyperspace. The only
+ * requirement is to be PIC called (PTA) before and
+ * any way (PTA/PTABS) after. According to Virtual
+ * to Physical mapping a simulator/emulator can easily
+ * tell where we came here from just looking at hopeless
+ * (PC) address.
+ *
+ * For debugging purposes:
+ * (r28) hopeless/loop address
+ * (r29) Original SR
+ * (r30) CPU type/Platform endianness
+ * (r31) FPU Support
+ * (r32) _start_kernel address
+ */
+ blink tr7, ZERO
diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c
index 4b449c4a6bad..f9bcc606127e 100644
--- a/arch/sh/kernel/init_task.c
+++ b/arch/sh/kernel/init_task.c
@@ -11,8 +11,8 @@ static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct pt_regs fake_swapper_regs;
struct mm_struct init_mm = INIT_MM(init_mm);
-
EXPORT_SYMBOL(init_mm);
/*
@@ -22,7 +22,7 @@ EXPORT_SYMBOL(init_mm);
* way process stacks are handled. This is done by having a special
* "init_task" linker map entry..
*/
-union thread_union init_thread_union
+union thread_union init_thread_union
__attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
index 501fe03e3715..71c9fde2fd90 100644
--- a/arch/sh/kernel/io.c
+++ b/arch/sh/kernel/io.c
@@ -61,73 +61,6 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
}
EXPORT_SYMBOL(memset_io);
-void __raw_readsl(unsigned long addr, void *datap, int len)
-{
- u32 *data;
-
- for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
- *data++ = ctrl_inl(addr);
-
- if (likely(len >= (0x20 >> 2))) {
- int tmp2, tmp3, tmp4, tmp5, tmp6;
-
- __asm__ __volatile__(
- "1: \n\t"
- "mov.l @%7, r0 \n\t"
- "mov.l @%7, %2 \n\t"
-#ifdef CONFIG_CPU_SH4
- "movca.l r0, @%0 \n\t"
-#else
- "mov.l r0, @%0 \n\t"
-#endif
- "mov.l @%7, %3 \n\t"
- "mov.l @%7, %4 \n\t"
- "mov.l @%7, %5 \n\t"
- "mov.l @%7, %6 \n\t"
- "mov.l @%7, r7 \n\t"
- "mov.l @%7, r0 \n\t"
- "mov.l %2, @(0x04,%0) \n\t"
- "mov #0x20>>2, %2 \n\t"
- "mov.l %3, @(0x08,%0) \n\t"
- "sub %2, %1 \n\t"
- "mov.l %4, @(0x0c,%0) \n\t"
- "cmp/hi %1, %2 ! T if 32 > len \n\t"
- "mov.l %5, @(0x10,%0) \n\t"
- "mov.l %6, @(0x14,%0) \n\t"
- "mov.l r7, @(0x18,%0) \n\t"
- "mov.l r0, @(0x1c,%0) \n\t"
- "bf.s 1b \n\t"
- " add #0x20, %0 \n\t"
- : "=&r" (data), "=&r" (len),
- "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
- "=&r" (tmp5), "=&r" (tmp6)
- : "r"(addr), "0" (data), "1" (len)
- : "r0", "r7", "t", "memory");
- }
-
- for (; len != 0; len--)
- *data++ = ctrl_inl(addr);
-}
-EXPORT_SYMBOL(__raw_readsl);
-
-void __raw_writesl(unsigned long addr, const void *data, int len)
-{
- if (likely(len != 0)) {
- int tmp1;
-
- __asm__ __volatile__ (
- "1: \n\t"
- "mov.l @%0+, %1 \n\t"
- "dt %3 \n\t"
- "bf.s 1b \n\t"
- " mov.l %1, @%4 \n\t"
- : "=&r" (data), "=&r" (tmp1)
- : "0" (data), "r" (len), "r"(addr)
- : "t", "memory");
- }
-}
-EXPORT_SYMBOL(__raw_writesl);
-
void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return sh_mv.mv_ioport_map(port, nr);
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index 142a4e5b7ebc..b3d0a03b4c76 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -1,5 +1,15 @@
/* Kernel module help for SH.
+ SHcompact version by Kaz Kojima and Paul Mundt.
+
+ SHmedia bits:
+
+ Copyright 2004 SuperH (UK) Ltd
+ Author: Richard Curnow
+
+ Based on the sh version, and on code from the sh64-specific parts of
+ modutils, originally written by Richard Curnow and Ben Gaster.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -21,12 +31,6 @@
#include <linux/string.h>
#include <linux/kernel.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt...)
-#endif
-
void *module_alloc(unsigned long size)
{
if (size == 0)
@@ -52,6 +56,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
return 0;
}
+#ifdef CONFIG_SUPERH32
#define COPY_UNALIGNED_WORD(sw, tw, align) \
{ \
void *__s = &(sw), *__t = &(tw); \
@@ -74,6 +79,10 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
break; \
} \
}
+#else
+/* One thing SHmedia doesn't screw up! */
+#define COPY_UNALIGNED_WORD(sw, tw, align) { (tw) = (sw); }
+#endif
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
@@ -89,8 +98,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
uint32_t value;
int align;
- DEBUGP("Applying relocate section %u to %u\n", relsec,
- sechdrs[relsec].sh_info);
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -102,17 +111,44 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
relocation = sym->st_value + rel[i].r_addend;
align = (int)location & 3;
+#ifdef CONFIG_SUPERH64
+ /* For text addresses, bit2 of the st_other field indicates
+ * whether the symbol is SHmedia (1) or SHcompact (0). If
+ * SHmedia, the LSB of the symbol needs to be asserted
+ * for the CPU to be in SHmedia mode when it starts executing
+ * the branch target. */
+ relocation |= (sym->st_other & 4);
+#endif
+
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_SH_DIR32:
- COPY_UNALIGNED_WORD (*location, value, align);
+ COPY_UNALIGNED_WORD (*location, value, align);
value += relocation;
- COPY_UNALIGNED_WORD (value, *location, align);
+ COPY_UNALIGNED_WORD (value, *location, align);
break;
case R_SH_REL32:
- relocation = (relocation - (Elf32_Addr) location);
- COPY_UNALIGNED_WORD (*location, value, align);
+ relocation = (relocation - (Elf32_Addr) location);
+ COPY_UNALIGNED_WORD (*location, value, align);
value += relocation;
- COPY_UNALIGNED_WORD (value, *location, align);
+ COPY_UNALIGNED_WORD (value, *location, align);
+ break;
+ case R_SH_IMM_LOW16:
+ *location = (*location & ~0x3fffc00) |
+ ((relocation & 0xffff) << 10);
+ break;
+ case R_SH_IMM_MEDLOW16:
+ *location = (*location & ~0x3fffc00) |
+ (((relocation >> 16) & 0xffff) << 10);
+ break;
+ case R_SH_IMM_LOW16_PCREL:
+ relocation -= (Elf32_Addr) location;
+ *location = (*location & ~0x3fffc00) |
+ ((relocation & 0xffff) << 10);
+ break;
+ case R_SH_IMM_MEDLOW16_PCREL:
+ relocation -= (Elf32_Addr) location;
+ *location = (*location & ~0x3fffc00) |
+ (((relocation >> 16) & 0xffff) << 10);
break;
default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process_32.c
index 6d7f2b07e491..9ab1926b9d10 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process_32.c
@@ -230,34 +230,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return fpvalid;
}
-/*
- * Capture the user space registers if the task is not running (in user space)
- */
-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
-{
- struct pt_regs ptregs;
-
- ptregs = *task_pt_regs(tsk);
- elf_core_copy_regs(regs, &ptregs);
-
- return 1;
-}
-
-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
-{
- int fpvalid = 0;
-
-#if defined(CONFIG_SH_FPU)
- fpvalid = !!tsk_used_math(tsk);
- if (fpvalid) {
- unlazy_fpu(tsk, task_pt_regs(tsk));
- memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
- }
-#endif
-
- return fpvalid;
-}
-
asmlinkage void ret_from_fork(void);
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
@@ -350,25 +322,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
unlazy_fpu(prev, task_pt_regs(prev));
#endif
-#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
- {
- struct pt_regs *regs;
-
- preempt_disable();
- regs = task_pt_regs(prev);
- if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
- int offset = (int)regs->regs[15];
-
- /* Reset stack pointer: clear critical region mark */
- regs->regs[15] = regs->regs[1];
- if (regs->pc < regs->regs[0])
- /* Go to rewind point */
- regs->pc = regs->regs[0] + offset;
- }
- preempt_enable_no_resched();
- }
-#endif
-
#ifdef CONFIG_MMU
/*
* Restore the kernel mode register
@@ -510,49 +463,3 @@ asmlinkage void break_point_trap(void)
force_sig(SIGTRAP, current);
}
-
-/*
- * Generic trap handler.
- */
-asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
- /* Rewind */
- regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
- if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
- SIGTRAP) == NOTIFY_STOP)
- return;
-
- force_sig(SIGTRAP, current);
-}
-
-/*
- * Special handler for BUG() traps.
- */
-asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
- /* Rewind */
- regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
- if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
- SIGTRAP) == NOTIFY_STOP)
- return;
-
-#ifdef CONFIG_BUG
- if (__kernel_text_address(instruction_pointer(regs))) {
- u16 insn = *(u16 *)instruction_pointer(regs);
- if (insn == TRAPA_BUG_OPCODE)
- handle_BUG(regs);
- }
-#endif
-
- force_sig(SIGTRAP, current);
-}
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
new file mode 100644
index 000000000000..cff3b7dc9c56
--- /dev/null
+++ b/arch/sh/kernel/process_64.c
@@ -0,0 +1,701 @@
+/*
+ * arch/sh/kernel/process_64.c
+ *
+ * This file handles the architecture-dependent parts of process handling..
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ * Copyright (C) 2003, 2004 Richard Curnow
+ *
+ * Started from SH3/4 version:
+ * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
+ *
+ * In turn started from i386 version:
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/ptrace.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+
+struct task_struct *last_task_used_math = NULL;
+
+static int hlt_counter = 1;
+
+#define HARD_IDLE_TIMEOUT (HZ / 3)
+
+void disable_hlt(void)
+{
+ hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+ hlt_counter--;
+}
+
+static int __init nohlt_setup(char *__unused)
+{
+ hlt_counter = 1;
+ return 1;
+}
+
+static int __init hlt_setup(char *__unused)
+{
+ hlt_counter = 0;
+ return 1;
+}
+
+__setup("nohlt", nohlt_setup);
+__setup("hlt", hlt_setup);
+
+static inline void hlt(void)
+{
+ __asm__ __volatile__ ("sleep" : : : "memory");
+}
+
+/*
+ * The idle loop on a uniprocessor SH..
+ */
+void cpu_idle(void)
+{
+ /* endless idle loop with no priority at all */
+ while (1) {
+ if (hlt_counter) {
+ while (!need_resched())
+ cpu_relax();
+ } else {
+ local_irq_disable();
+ while (!need_resched()) {
+ local_irq_enable();
+ hlt();
+ local_irq_disable();
+ }
+ local_irq_enable();
+ }
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+
+}
+
+void machine_restart(char * __unused)
+{
+ extern void phys_stext(void);
+
+ phys_stext();
+}
+
+void machine_halt(void)
+{
+ for (;;);
+}
+
+void machine_power_off(void)
+{
+#if 0
+ /* Disable watchdog timer */
+ ctrl_outl(0xa5000000, WTCSR);
+ /* Configure deep standby on sleep */
+ ctrl_outl(0x03, STBCR);
+#endif
+
+ __asm__ __volatile__ (
+ "sleep\n\t"
+ "synci\n\t"
+ "nop;nop;nop;nop\n\t"
+ );
+
+ panic("Unexpected wakeup!\n");
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+ unsigned long long ah, al, bh, bl, ch, cl;
+
+ printk("\n");
+
+ ah = (regs->pc) >> 32;
+ al = (regs->pc) & 0xffffffff;
+ bh = (regs->regs[18]) >> 32;
+ bl = (regs->regs[18]) & 0xffffffff;
+ ch = (regs->regs[15]) >> 32;
+ cl = (regs->regs[15]) & 0xffffffff;
+ printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->sr) >> 32;
+ al = (regs->sr) & 0xffffffff;
+ asm volatile ("getcon " __TEA ", %0" : "=r" (bh));
+ asm volatile ("getcon " __TEA ", %0" : "=r" (bl));
+ bh = (bh) >> 32;
+ bl = (bl) & 0xffffffff;
+ asm volatile ("getcon " __KCR0 ", %0" : "=r" (ch));
+ asm volatile ("getcon " __KCR0 ", %0" : "=r" (cl));
+ ch = (ch) >> 32;
+ cl = (cl) & 0xffffffff;
+ printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[0]) >> 32;
+ al = (regs->regs[0]) & 0xffffffff;
+ bh = (regs->regs[1]) >> 32;
+ bl = (regs->regs[1]) & 0xffffffff;
+ ch = (regs->regs[2]) >> 32;
+ cl = (regs->regs[2]) & 0xffffffff;
+ printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[3]) >> 32;
+ al = (regs->regs[3]) & 0xffffffff;
+ bh = (regs->regs[4]) >> 32;
+ bl = (regs->regs[4]) & 0xffffffff;
+ ch = (regs->regs[5]) >> 32;
+ cl = (regs->regs[5]) & 0xffffffff;
+ printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[6]) >> 32;
+ al = (regs->regs[6]) & 0xffffffff;
+ bh = (regs->regs[7]) >> 32;
+ bl = (regs->regs[7]) & 0xffffffff;
+ ch = (regs->regs[8]) >> 32;
+ cl = (regs->regs[8]) & 0xffffffff;
+ printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[9]) >> 32;
+ al = (regs->regs[9]) & 0xffffffff;
+ bh = (regs->regs[10]) >> 32;
+ bl = (regs->regs[10]) & 0xffffffff;
+ ch = (regs->regs[11]) >> 32;
+ cl = (regs->regs[11]) & 0xffffffff;
+ printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[12]) >> 32;
+ al = (regs->regs[12]) & 0xffffffff;
+ bh = (regs->regs[13]) >> 32;
+ bl = (regs->regs[13]) & 0xffffffff;
+ ch = (regs->regs[14]) >> 32;
+ cl = (regs->regs[14]) & 0xffffffff;
+ printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[16]) >> 32;
+ al = (regs->regs[16]) & 0xffffffff;
+ bh = (regs->regs[17]) >> 32;
+ bl = (regs->regs[17]) & 0xffffffff;
+ ch = (regs->regs[19]) >> 32;
+ cl = (regs->regs[19]) & 0xffffffff;
+ printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[20]) >> 32;
+ al = (regs->regs[20]) & 0xffffffff;
+ bh = (regs->regs[21]) >> 32;
+ bl = (regs->regs[21]) & 0xffffffff;
+ ch = (regs->regs[22]) >> 32;
+ cl = (regs->regs[22]) & 0xffffffff;
+ printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[23]) >> 32;
+ al = (regs->regs[23]) & 0xffffffff;
+ bh = (regs->regs[24]) >> 32;
+ bl = (regs->regs[24]) & 0xffffffff;
+ ch = (regs->regs[25]) >> 32;
+ cl = (regs->regs[25]) & 0xffffffff;
+ printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[26]) >> 32;
+ al = (regs->regs[26]) & 0xffffffff;
+ bh = (regs->regs[27]) >> 32;
+ bl = (regs->regs[27]) & 0xffffffff;
+ ch = (regs->regs[28]) >> 32;
+ cl = (regs->regs[28]) & 0xffffffff;
+ printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[29]) >> 32;
+ al = (regs->regs[29]) & 0xffffffff;
+ bh = (regs->regs[30]) >> 32;
+ bl = (regs->regs[30]) & 0xffffffff;
+ ch = (regs->regs[31]) >> 32;
+ cl = (regs->regs[31]) & 0xffffffff;
+ printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[32]) >> 32;
+ al = (regs->regs[32]) & 0xffffffff;
+ bh = (regs->regs[33]) >> 32;
+ bl = (regs->regs[33]) & 0xffffffff;
+ ch = (regs->regs[34]) >> 32;
+ cl = (regs->regs[34]) & 0xffffffff;
+ printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[35]) >> 32;
+ al = (regs->regs[35]) & 0xffffffff;
+ bh = (regs->regs[36]) >> 32;
+ bl = (regs->regs[36]) & 0xffffffff;
+ ch = (regs->regs[37]) >> 32;
+ cl = (regs->regs[37]) & 0xffffffff;
+ printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[38]) >> 32;
+ al = (regs->regs[38]) & 0xffffffff;
+ bh = (regs->regs[39]) >> 32;
+ bl = (regs->regs[39]) & 0xffffffff;
+ ch = (regs->regs[40]) >> 32;
+ cl = (regs->regs[40]) & 0xffffffff;
+ printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[41]) >> 32;
+ al = (regs->regs[41]) & 0xffffffff;
+ bh = (regs->regs[42]) >> 32;
+ bl = (regs->regs[42]) & 0xffffffff;
+ ch = (regs->regs[43]) >> 32;
+ cl = (regs->regs[43]) & 0xffffffff;
+ printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[44]) >> 32;
+ al = (regs->regs[44]) & 0xffffffff;
+ bh = (regs->regs[45]) >> 32;
+ bl = (regs->regs[45]) & 0xffffffff;
+ ch = (regs->regs[46]) >> 32;
+ cl = (regs->regs[46]) & 0xffffffff;
+ printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[47]) >> 32;
+ al = (regs->regs[47]) & 0xffffffff;
+ bh = (regs->regs[48]) >> 32;
+ bl = (regs->regs[48]) & 0xffffffff;
+ ch = (regs->regs[49]) >> 32;
+ cl = (regs->regs[49]) & 0xffffffff;
+ printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[50]) >> 32;
+ al = (regs->regs[50]) & 0xffffffff;
+ bh = (regs->regs[51]) >> 32;
+ bl = (regs->regs[51]) & 0xffffffff;
+ ch = (regs->regs[52]) >> 32;
+ cl = (regs->regs[52]) & 0xffffffff;
+ printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[53]) >> 32;
+ al = (regs->regs[53]) & 0xffffffff;
+ bh = (regs->regs[54]) >> 32;
+ bl = (regs->regs[54]) & 0xffffffff;
+ ch = (regs->regs[55]) >> 32;
+ cl = (regs->regs[55]) & 0xffffffff;
+ printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[56]) >> 32;
+ al = (regs->regs[56]) & 0xffffffff;
+ bh = (regs->regs[57]) >> 32;
+ bl = (regs->regs[57]) & 0xffffffff;
+ ch = (regs->regs[58]) >> 32;
+ cl = (regs->regs[58]) & 0xffffffff;
+ printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[59]) >> 32;
+ al = (regs->regs[59]) & 0xffffffff;
+ bh = (regs->regs[60]) >> 32;
+ bl = (regs->regs[60]) & 0xffffffff;
+ ch = (regs->regs[61]) >> 32;
+ cl = (regs->regs[61]) & 0xffffffff;
+ printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[62]) >> 32;
+ al = (regs->regs[62]) & 0xffffffff;
+ bh = (regs->tregs[0]) >> 32;
+ bl = (regs->tregs[0]) & 0xffffffff;
+ ch = (regs->tregs[1]) >> 32;
+ cl = (regs->tregs[1]) & 0xffffffff;
+ printk("R62 : %08Lx%08Lx T0 : %08Lx%08Lx T1 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->tregs[2]) >> 32;
+ al = (regs->tregs[2]) & 0xffffffff;
+ bh = (regs->tregs[3]) >> 32;
+ bl = (regs->tregs[3]) & 0xffffffff;
+ ch = (regs->tregs[4]) >> 32;
+ cl = (regs->tregs[4]) & 0xffffffff;
+ printk("T2 : %08Lx%08Lx T3 : %08Lx%08Lx T4 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->tregs[5]) >> 32;
+ al = (regs->tregs[5]) & 0xffffffff;
+ bh = (regs->tregs[6]) >> 32;
+ bl = (regs->tregs[6]) & 0xffffffff;
+ ch = (regs->tregs[7]) >> 32;
+ cl = (regs->tregs[7]) & 0xffffffff;
+ printk("T5 : %08Lx%08Lx T6 : %08Lx%08Lx T7 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ /*
+ * If we're in kernel mode, dump the stack too..
+ */
+ if (!user_mode(regs)) {
+ void show_stack(struct task_struct *tsk, unsigned long *sp);
+ unsigned long sp = regs->regs[15] & 0xffffffff;
+ struct task_struct *tsk = get_current();
+
+ tsk->thread.kregs = regs;
+
+ show_stack(tsk, (unsigned long *)sp);
+ }
+}
+
+struct task_struct * alloc_task_struct(void)
+{
+ /* Get task descriptor pages */
+ return (struct task_struct *)
+ __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
+}
+
+void free_task_struct(struct task_struct *p)
+{
+ free_pages((unsigned long) p, get_order(THREAD_SIZE));
+}
+
+/*
+ * Create a kernel thread
+ */
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+ do_exit(fn(arg));
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be freed until both the parent and the child have exited.
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.regs[2] = (unsigned long)arg;
+ regs.regs[3] = (unsigned long)fn;
+
+ regs.pc = (unsigned long)kernel_thread_helper;
+ regs.sr = (1 << 30);
+
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+ &regs, 0, NULL, NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ /*
+ * See arch/sparc/kernel/process.c for the precedent for doing
+ * this -- RPC.
+ *
+ * The SH-5 FPU save/restore approach relies on
+ * last_task_used_math pointing to a live task_struct. When
+ * another task tries to use the FPU for the 1st time, the FPUDIS
+ * trap handling (see arch/sh/kernel/cpu/sh5/fpu.c) will save the
+ * existing FPU state to the FP regs field within
+ * last_task_used_math before re-loading the new task's FPU state
+ * (or initialising it if the FPU has been used before). So if
+ * last_task_used_math is stale, and its page has already been
+ * re-allocated for another use, the consequences are rather
+ * grim. Unless we null it here, there is no other path through
+ * which it would get safely nulled.
+ */
+#ifdef CONFIG_SH_FPU
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+ }
+#endif
+}
+
+void flush_thread(void)
+{
+
+ /* Called by fs/exec.c (flush_old_exec) to remove traces of a
+ * previously running executable. */
+#ifdef CONFIG_SH_FPU
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+ }
+ /* Force FPU state to be reinitialised after exec */
+ clear_used_math();
+#endif
+
+ /* if we are a kernel thread, about to change to user thread,
+ * update kreg
+ */
+ if(current->thread.kregs==&fake_swapper_regs) {
+ current->thread.kregs =
+ ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
+ current->thread.uregs = current->thread.kregs;
+ }
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+ /* do nothing */
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+#ifdef CONFIG_SH_FPU
+ int fpvalid;
+ struct task_struct *tsk = current;
+
+ fpvalid = !!tsk_used_math(tsk);
+ if (fpvalid) {
+ if (current == last_task_used_math) {
+ enable_fpu();
+ save_fpu(tsk, regs);
+ disable_fpu();
+ last_task_used_math = 0;
+ regs->sr |= SR_FD;
+ }
+
+ memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+ }
+
+ return fpvalid;
+#else
+ return 0; /* Task didn't use the fpu at all. */
+#endif
+}
+
+asmlinkage void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ unsigned long unused,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs *childregs;
+ unsigned long long se; /* Sign extension */
+
+#ifdef CONFIG_SH_FPU
+ if(last_task_used_math == current) {
+ enable_fpu();
+ save_fpu(current, regs);
+ disable_fpu();
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+#endif
+ /* Copy from sh version */
+ childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
+
+ *childregs = *regs;
+
+ if (user_mode(regs)) {
+ childregs->regs[15] = usp;
+ p->thread.uregs = childregs;
+ } else {
+ childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+ }
+
+ childregs->regs[9] = 0; /* Set return value for child */
+ childregs->sr |= SR_FD; /* Invalidate FPU flag */
+
+ p->thread.sp = (unsigned long) childregs;
+ p->thread.pc = (unsigned long) ret_from_fork;
+
+ /*
+ * Sign extend the edited stack.
+ * Note that thread.pc and thread.pc will stay
+ * 32-bit wide and context switch must take care
+ * of NEFF sign extension.
+ */
+
+ se = childregs->regs[15];
+ se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se;
+ childregs->regs[15] = se;
+
+ return 0;
+}
+
+asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+}
+
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ if (!newsp)
+ newsp = pregs->regs[15];
+ return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char *ufilename, char **uargv,
+ char **uenvp, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ int error;
+ char *filename;
+
+ lock_kernel();
+ filename = getname((char __user *)ufilename);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+
+ error = do_execve(filename,
+ (char __user * __user *)uargv,
+ (char __user * __user *)uenvp,
+ pregs);
+ if (error == 0) {
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ }
+ putname(filename);
+out:
+ unlock_kernel();
+ return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void interruptible_sleep_on(wait_queue_head_t *q);
+
+#define mid_sched ((unsigned long) interruptible_sleep_on)
+
+static int in_sh64_switch_to(unsigned long pc)
+{
+ extern char __sh64_switch_to_end;
+ /* For a sleeping task, the PC is somewhere in the middle of the function,
+ so we don't have to worry about masking the LSB off */
+ return (pc >= (unsigned long) sh64_switch_to) &&
+ (pc < (unsigned long) &__sh64_switch_to_end);
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long schedule_fp;
+ unsigned long sh64_switch_to_fp;
+ unsigned long schedule_caller_pc;
+ unsigned long pc;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ /*
+ * The same comment as on the Alpha applies here, too ...
+ */
+ pc = thread_saved_pc(p);
+
+#ifdef CONFIG_FRAME_POINTER
+ if (in_sh64_switch_to(pc)) {
+ sh64_switch_to_fp = (long) p->thread.sp;
+ /* r14 is saved at offset 4 in the sh64_switch_to frame */
+ schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
+
+ /* and the caller of 'schedule' is (currently!) saved at offset 24
+ in the frame of schedule (from disasm) */
+ schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
+ return schedule_caller_pc;
+ }
+#endif
+ return pc;
+}
+
+/* Provide a /proc/asids file that lists out the
+ ASIDs currently associated with the processes. (If the DM.PC register is
+ examined through the debug link, this shows ASID + PC. To make use of this,
+ the PID->ASID relationship needs to be known. This is primarily for
+ debugging.)
+ */
+
+#if defined(CONFIG_SH64_PROC_ASIDS)
+static int
+asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+ int len=0;
+ struct task_struct *p;
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ int pid = p->pid;
+
+ if (!pid)
+ continue;
+ if (p->mm)
+ len += sprintf(buf+len, "%5d : %02lx\n", pid,
+ asid_cache(smp_processor_id()));
+ else
+ len += sprintf(buf+len, "%5d : (none)\n", pid);
+ }
+ read_unlock(&tasklist_lock);
+ *eof = 1;
+ return len;
+}
+
+static int __init register_proc_asids(void)
+{
+ create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
+ return 0;
+}
+__initcall(register_proc_asids);
+#endif
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace_32.c
index ac725f0aeb72..ce0664a58b49 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -6,7 +6,7 @@
* edited by Linus Torvalds
*
* SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
- *
+ * Audit support: Yuichi Nakamura <ynakam@hitachisoft.jp>
*/
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -19,6 +19,7 @@
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/io.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -248,15 +249,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage void do_syscall_trace(void)
+asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
{
struct task_struct *tsk = current;
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
+ regs->regs[0]);
+
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
!test_thread_flag(TIF_SINGLESTEP))
- return;
+ goto out;
if (!(tsk->ptrace & PT_PTRACED))
- return;
+ goto out;
+
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
@@ -271,4 +277,11 @@ asmlinkage void do_syscall_trace(void)
send_sig(tsk->exit_code, tsk, 1);
tsk->exit_code = 0;
}
+
+out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[3],
+ regs->regs[4], regs->regs[5],
+ regs->regs[6], regs->regs[7]);
+
}
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
new file mode 100644
index 000000000000..f6fbdfa6876d
--- /dev/null
+++ b/arch/sh/kernel/ptrace_64.c
@@ -0,0 +1,341 @@
+/*
+ * arch/sh/kernel/ptrace_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * Started from SH3/4 version:
+ * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
+ *
+ * Original x86 implementation:
+ * By Ross Biro 1/23/92
+ * edited by Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/audit.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+
+/* This mask defines the bits of the SR which the user is not allowed to
+ change, which are everything except S, Q, M, PR, SZ, FR. */
+#define SR_MASK (0xffff8cfd)
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * This routine will get a word from the user area in the process kernel stack.
+ */
+static inline int get_stack_long(struct task_struct *task, int offset)
+{
+ unsigned char *stack;
+
+ stack = (unsigned char *)(task->thread.uregs);
+ stack += offset;
+ return (*((int *)stack));
+}
+
+static inline unsigned long
+get_fpu_long(struct task_struct *task, unsigned long addr)
+{
+ unsigned long tmp;
+ struct pt_regs *regs;
+ regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
+
+ if (!tsk_used_math(task)) {
+ if (addr == offsetof(struct user_fpu_struct, fpscr)) {
+ tmp = FPSCR_INIT;
+ } else {
+ tmp = 0xffffffffUL; /* matches initial value in fpu.c */
+ }
+ return tmp;
+ }
+
+ if (last_task_used_math == task) {
+ enable_fpu();
+ save_fpu(task, regs);
+ disable_fpu();
+ last_task_used_math = 0;
+ regs->sr |= SR_FD;
+ }
+
+ tmp = ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)];
+ return tmp;
+}
+
+/*
+ * This routine will put a word into the user area in the process kernel stack.
+ */
+static inline int put_stack_long(struct task_struct *task, int offset,
+ unsigned long data)
+{
+ unsigned char *stack;
+
+ stack = (unsigned char *)(task->thread.uregs);
+ stack += offset;
+ *(unsigned long *) stack = data;
+ return 0;
+}
+
+static inline int
+put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
+{
+ struct pt_regs *regs;
+
+ regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
+
+ if (!tsk_used_math(task)) {
+ fpinit(&task->thread.fpu.hard);
+ set_stopped_child_used_math(task);
+ } else if (last_task_used_math == task) {
+ enable_fpu();
+ save_fpu(task, regs);
+ disable_fpu();
+ last_task_used_math = 0;
+ regs->sr |= SR_FD;
+ }
+
+ ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)] = data;
+ return 0;
+}
+
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+ int ret;
+
+ switch (request) {
+ /* when I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
+ break;
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR: {
+ unsigned long tmp;
+
+ ret = -EIO;
+ if ((addr & 3) || addr < 0)
+ break;
+
+ if (addr < sizeof(struct pt_regs))
+ tmp = get_stack_long(child, addr);
+ else if ((addr >= offsetof(struct user, fpu)) &&
+ (addr < offsetof(struct user, u_fpvalid))) {
+ tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
+ } else if (addr == offsetof(struct user, u_fpvalid)) {
+ tmp = !!tsk_used_math(child);
+ } else {
+ break;
+ }
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
+ }
+
+ /* when I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = generic_ptrace_pokedata(child, addr, data);
+ break;
+
+ case PTRACE_POKEUSR:
+ /* write the word at location addr in the USER area. We must
+ disallow any changes to certain SR bits or u_fpvalid, since
+ this could crash the kernel or result in a security
+ loophole. */
+ ret = -EIO;
+ if ((addr & 3) || addr < 0)
+ break;
+
+ if (addr < sizeof(struct pt_regs)) {
+ /* Ignore change of top 32 bits of SR */
+ if (addr == offsetof (struct pt_regs, sr)+4)
+ {
+ ret = 0;
+ break;
+ }
+ /* If lower 32 bits of SR, ignore non-user bits */
+ if (addr == offsetof (struct pt_regs, sr))
+ {
+ long cursr = get_stack_long(child, addr);
+ data &= ~(SR_MASK);
+ data |= (cursr & SR_MASK);
+ }
+ ret = put_stack_long(child, addr, data);
+ }
+ else if ((addr >= offsetof(struct user, fpu)) &&
+ (addr < offsetof(struct user, u_fpvalid))) {
+ ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data);
+ }
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+ if (request == PTRACE_SYSCALL)
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ child->exit_code = data;
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+/*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL: {
+ ret = 0;
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ wake_up_process(child);
+ break;
+ }
+
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
+ struct pt_regs *regs;
+
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ if ((child->ptrace & PT_DTRACE) == 0) {
+ /* Spurious delayed TF traps may occur */
+ child->ptrace |= PT_DTRACE;
+ }
+
+ regs = child->thread.uregs;
+
+ regs->sr |= SR_SSTEP; /* auto-resetting upon exception */
+
+ child->exit_code = data;
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+ return ret;
+}
+
+asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
+{
+#define WPC_DBRMODE 0x0d104008
+ static int first_call = 1;
+
+ lock_kernel();
+ if (first_call) {
+ /* Set WPC.DBRMODE to 0. This makes all debug events get
+ * delivered through RESVEC, i.e. into the handlers in entry.S.
+ * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
+ * would normally be left set to 1, which makes debug events get
+ * delivered through DBRVEC, i.e. into the remote gdb's
+ * handlers. This prevents ptrace getting them, and confuses
+ * the remote gdb.) */
+ printk("DBRMODE set to 0 to permit native debugging\n");
+ poke_real_address_q(WPC_DBRMODE, 0);
+ first_call = 0;
+ }
+ unlock_kernel();
+
+ return sys_ptrace(request, pid, addr, data);
+}
+
+asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit)
+{
+ struct task_struct *tsk = current;
+
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
+ regs->regs[9]);
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+ !test_thread_flag(TIF_SINGLESTEP))
+ goto out;
+ if (!(tsk->ptrace & PT_PTRACED))
+ goto out;
+
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+ !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (tsk->exit_code) {
+ send_sig(tsk->exit_code, tsk, 1);
+ tsk->exit_code = 0;
+ }
+
+out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[1],
+ regs->regs[2], regs->regs[3],
+ regs->regs[4], regs->regs[5]);
+}
+
+/* Called with interrupts disabled */
+asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs)
+{
+ /* This is called after a single step exception (DEBUGSS).
+ There is no need to change the PC, as it is a post-execution
+ exception, as entry.S does not do anything to the PC for DEBUGSS.
+ We need to clear the Single Step setting in SR to avoid
+ continually stepping. */
+ local_irq_enable();
+ regs->sr &= ~SR_SSTEP;
+ force_sig(SIGTRAP, current);
+}
+
+/* Called with interrupts disabled */
+asmlinkage void do_software_break_point(unsigned long long vec,
+ struct pt_regs *regs)
+{
+ /* We need to forward step the PC, to counteract the backstep done
+ in signal.c. */
+ local_irq_enable();
+ force_sig(SIGTRAP, current);
+ regs->pc += 4;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+ /* nothing to do.. */
+}
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 4156aac8c27d..855cdf9d85b1 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -26,6 +26,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
+#include <asm/elf.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -78,12 +79,25 @@ EXPORT_SYMBOL(memory_start);
unsigned long memory_end = 0;
EXPORT_SYMBOL(memory_end);
+int l1i_cache_shape, l1d_cache_shape, l2_cache_shape;
+
static int __init early_parse_mem(char *p)
{
unsigned long size;
- memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+ memory_start = (unsigned long)__va(__MEMORY_START);
size = memparse(p, &p);
+
+ if (size > __MEMORY_SIZE) {
+ static char msg[] __initdata = KERN_ERR
+ "Using mem= to increase the size of kernel memory "
+ "is not allowed.\n"
+ " Recompile the kernel with the correct value for "
+ "CONFIG_MEMORY_SIZE.\n";
+ printk(msg);
+ return 0;
+ }
+
memory_end = memory_start + size;
return 0;
@@ -243,7 +257,7 @@ void __init setup_arch(char **cmdline_p)
data_resource.start = virt_to_phys(_etext);
data_resource.end = virt_to_phys(_edata)-1;
- memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+ memory_start = (unsigned long)__va(__MEMORY_START);
if (!memory_end)
memory_end = memory_start + __MEMORY_SIZE;
@@ -294,20 +308,23 @@ void __init setup_arch(char **cmdline_p)
}
static const char *cpu_name[] = {
+ [CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263",
[CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619",
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
[CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720",
- [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
- [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
- [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
- [CPU_SH7760] = "SH7760",
+ [CPU_SH7721] = "SH7721", [CPU_SH7729] = "SH7729",
+ [CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S",
+ [CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751",
+ [CPU_SH7751R] = "SH7751R", [CPU_SH7760] = "SH7760",
[CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
- [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
- [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
- [CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722",
- [CPU_SHX3] = "SH-X3", [CPU_SH_NONE] = "Unknown"
+ [CPU_SH7763] = "SH7763", [CPU_SH7770] = "SH7770",
+ [CPU_SH7780] = "SH7780", [CPU_SH7781] = "SH7781",
+ [CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785",
+ [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3",
+ [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103",
+ [CPU_SH_NONE] = "Unknown"
};
const char *get_cpu_subtype(struct sh_cpuinfo *c)
@@ -410,7 +427,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
static void c_stop(struct seq_file *m, void *v)
{
}
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms_32.c
index e1a6de9088b5..e1a6de9088b5 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
new file mode 100644
index 000000000000..8004c38d3d37
--- /dev/null
+++ b/arch/sh/kernel/sh_ksyms_64.c
@@ -0,0 +1,55 @@
+/*
+ * arch/sh/kernel/sh_ksyms_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/screen_info.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+
+/* platform dependent support */
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(kernel_thread);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__put_user_asm_l);
+EXPORT_SYMBOL(__get_user_asm_l);
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__ndelay);
+
+/* Ugh. These come in from libgcc.a at link time. */
+#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
+
+DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__muldi3);
+DECLARE_EXPORT(__udivsi3);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal_32.c
index ca754fd42437..f6b5fbfe75c4 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal_32.c
@@ -507,24 +507,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
ctrl_inw(regs->pc - 4));
break;
}
-#ifdef CONFIG_GUSA
- } else {
- /* gUSA handling */
- preempt_disable();
-
- if (regs->regs[15] >= 0xc0000000) {
- int offset = (int)regs->regs[15];
-
- /* Reset stack pointer: clear critical region mark */
- regs->regs[15] = regs->regs[1];
- if (regs->pc < regs->regs[0])
- /* Go to rewind point #1 */
- regs->pc = regs->regs[0] + offset -
- instruction_size(ctrl_inw(regs->pc-4));
- }
-
- preempt_enable_no_resched();
-#endif
}
/* Set up the stack frame */
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
new file mode 100644
index 000000000000..80bde19d445b
--- /dev/null
+++ b/arch/sh/kernel/signal_64.c
@@ -0,0 +1,751 @@
+/*
+ * arch/sh/kernel/signal_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 Paul Mundt
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/personality.h>
+#include <linux/freezer.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#define REG_RET 9
+#define REG_ARG1 2
+#define REG_ARG2 3
+#define REG_ARG3 4
+#define REG_SP 15
+#define REG_PR 18
+#define REF_REG_RET regs->regs[REG_RET]
+#define REF_REG_SP regs->regs[REG_SP]
+#define DEREF_REG_PR regs->regs[REG_PR]
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+asmlinkage int
+sys_sigsuspend(old_sigset_t mask,
+ unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs * regs)
+{
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sighand->siglock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ REF_REG_RET = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ regs->pc += 4; /* because sys_sigreturn decrements the pc */
+ if (do_signal(regs, &saveset)) {
+ /* pc now points at signal handler. Need to decrement
+ it because entry.S will increment it. */
+ regs->pc -= 4;
+ return -EINTR;
+ }
+ }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+ unsigned long r4, unsigned long r5, unsigned long r6,
+ unsigned long r7,
+ struct pt_regs * regs)
+{
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ REF_REG_RET = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ regs->pc += 4; /* because sys_sigreturn decrements the pc */
+ if (do_signal(regs, &saveset)) {
+ /* pc now points at signal handler. Need to decrement
+ it because entry.S will increment it. */
+ regs->pc -= 4;
+ return -EINTR;
+ }
+ }
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+ struct old_sigaction __user *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+ unsigned long r4, unsigned long r5, unsigned long r6,
+ unsigned long r7,
+ struct pt_regs * regs)
+{
+ return do_sigaltstack(uss, uoss, REF_REG_SP);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+ struct sigcontext sc;
+ unsigned long extramask[_NSIG_WORDS-1];
+ long long retcode[2];
+};
+
+struct rt_sigframe
+{
+ struct siginfo __user *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ long long retcode[2];
+};
+
+#ifdef CONFIG_SH_FPU
+static inline int
+restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+ int err = 0;
+ int fpvalid;
+
+ err |= __get_user (fpvalid, &sc->sc_fpvalid);
+ conditional_used_math(fpvalid);
+ if (! fpvalid)
+ return err;
+
+ if (current == last_task_used_math) {
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+
+ err |= __copy_from_user(&current->thread.fpu.hard, &sc->sc_fpregs[0],
+ (sizeof(long long) * 32) + (sizeof(int) * 1));
+
+ return err;
+}
+
+static inline int
+setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+ int err = 0;
+ int fpvalid;
+
+ fpvalid = !!used_math();
+ err |= __put_user(fpvalid, &sc->sc_fpvalid);
+ if (! fpvalid)
+ return err;
+
+ if (current == last_task_used_math) {
+ enable_fpu();
+ save_fpu(current, regs);
+ disable_fpu();
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+
+ err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.fpu.hard,
+ (sizeof(long long) * 32) + (sizeof(int) * 1));
+ clear_used_math();
+
+ return err;
+}
+#else
+static inline int
+restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+ return 0;
+}
+static inline int
+setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+ return 0;
+}
+#endif
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
+{
+ unsigned int err = 0;
+ unsigned long long current_sr, new_sr;
+#define SR_MASK 0xffff8cfd
+
+#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
+
+ COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
+ COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
+ COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
+ COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
+ COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
+ COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
+ COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
+ COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
+ COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
+ COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
+ COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
+ COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
+ COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
+ COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
+ COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
+ COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
+ COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
+ COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
+
+ /* Prevent the signal handler manipulating SR in a way that can
+ crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
+ modified */
+ current_sr = regs->sr;
+ err |= __get_user(new_sr, &sc->sc_sr);
+ regs->sr &= SR_MASK;
+ regs->sr |= (new_sr & ~SR_MASK);
+
+ COPY(pc);
+
+#undef COPY
+
+ /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
+ * has been restored above.) */
+ err |= restore_sigcontext_fpu(regs, sc);
+
+ regs->syscall_nr = -1; /* disable syscall checks */
+ err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
+ return err;
+}
+
+asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs * regs)
+{
+ struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
+ sigset_t set;
+ long long ret;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+
+ if (__get_user(set.sig[0], &frame->sc.oldmask)
+ || (_NSIG_WORDS > 1
+ && __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->sc, &ret))
+ goto badframe;
+ regs->pc -= 4;
+
+ return (int) ret;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs * regs)
+{
+ struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
+ sigset_t set;
+ stack_t __user st;
+ long long ret;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
+ goto badframe;
+ regs->pc -= 4;
+
+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, REF_REG_SP);
+
+ return (int) ret;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+ unsigned long mask)
+{
+ int err = 0;
+
+ /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
+ err |= setup_sigcontext_fpu(regs, sc);
+
+#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
+
+ COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
+ COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
+ COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
+ COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
+ COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
+ COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
+ COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
+ COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
+ COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
+ COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
+ COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
+ COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
+ COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
+ COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
+ COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
+ COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
+ COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
+ COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
+ COPY(sr); COPY(pc);
+
+#undef COPY
+
+ err |= __put_user(mask, &sc->oldmask);
+
+ return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+ return (void __user *)((sp - frame_size) & -8ul);
+}
+
+void sa_default_restorer(void); /* See comments below */
+void sa_default_rt_restorer(void); /* See comments below */
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct sigframe __user *frame;
+ int err = 0;
+ int signal;
+
+ frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ signal = current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32
+ ? current_thread_info()->exec_domain->signal_invmap[sig]
+ : sig;
+
+ err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+ /* Give up earlier as i386, in case */
+ if (err)
+ goto give_sigsegv;
+
+ if (_NSIG_WORDS > 1) {
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask)); }
+
+ /* Give up earlier as i386, in case */
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
+
+ /*
+ * On SH5 all edited pointers are subject to NEFF
+ */
+ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+ (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+ } else {
+ /*
+ * Different approach on SH5.
+ * . Endianness independent asm code gets placed in entry.S .
+ * This is limited to four ASM instructions corresponding
+ * to two long longs in size.
+ * . err checking is done on the else branch only
+ * . flush_icache_range() is called upon __put_user() only
+ * . all edited pointers are subject to NEFF
+ * . being code, linker turns ShMedia bit on, always
+ * dereference index -1.
+ */
+ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
+ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+ (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+
+ if (__copy_to_user(frame->retcode,
+ (unsigned long long)sa_default_restorer & (~1), 16) != 0)
+ goto give_sigsegv;
+
+ /* Cohere the trampoline with the I-cache. */
+ flush_cache_sigtramp(DEREF_REG_PR-1);
+ }
+
+ /*
+ * Set up registers for signal handler.
+ * All edited pointers are subject to NEFF.
+ */
+ regs->regs[REG_SP] = (unsigned long) frame;
+ regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
+ (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
+ regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
+
+ /* FIXME:
+ The glibc profiling support for SH-5 needs to be passed a sigcontext
+ so it can retrieve the PC. At some point during 2003 the glibc
+ support was changed to receive the sigcontext through the 2nd
+ argument, but there are still versions of libc.so in use that use
+ the 3rd argument. Until libc.so is stabilised, pass the sigcontext
+ through both 2nd and 3rd arguments.
+ */
+
+ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
+ regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
+
+ regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
+
+ set_fs(USER_DS);
+
+#if DEBUG_SIG
+ /* Broken %016Lx */
+ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+ signal,
+ current->comm, current->pid, frame,
+ regs->pc >> 32, regs->pc & 0xffffffff,
+ DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
+#endif
+
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame;
+ int err = 0;
+ int signal;
+
+ frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ signal = current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32
+ ? current_thread_info()->exec_domain->signal_invmap[sig]
+ : sig;
+
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= copy_siginfo_to_user(&frame->info, info);
+
+ /* Give up earlier as i386, in case */
+ if (err)
+ goto give_sigsegv;
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user((void *)current->sas_ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext,
+ regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Give up earlier as i386, in case */
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
+
+ /*
+ * On SH5 all edited pointers are subject to NEFF
+ */
+ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+ (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+ } else {
+ /*
+ * Different approach on SH5.
+ * . Endianness independent asm code gets placed in entry.S .
+ * This is limited to four ASM instructions corresponding
+ * to two long longs in size.
+ * . err checking is done on the else branch only
+ * . flush_icache_range() is called upon __put_user() only
+ * . all edited pointers are subject to NEFF
+ * . being code, linker turns ShMedia bit on, always
+ * dereference index -1.
+ */
+
+ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
+ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+ (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+
+ if (__copy_to_user(frame->retcode,
+ (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0)
+ goto give_sigsegv;
+
+ flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
+ }
+
+ /*
+ * Set up registers for signal handler.
+ * All edited pointers are subject to NEFF.
+ */
+ regs->regs[REG_SP] = (unsigned long) frame;
+ regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
+ (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
+ regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
+ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
+ regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
+ regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
+
+ set_fs(USER_DS);
+
+#if DEBUG_SIG
+ /* Broken %016Lx */
+ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+ signal,
+ current->comm, current->pid, frame,
+ regs->pc >> 32, regs->pc & 0xffffffff,
+ DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
+#endif
+
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+ sigset_t *oldset, struct pt_regs * regs)
+{
+ /* Are we from a system call? */
+ if (regs->syscall_nr >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->regs[REG_RET]) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ regs->regs[REG_RET] = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->regs[REG_RET] = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ /* Decode syscall # */
+ regs->regs[REG_RET] = regs->syscall_nr;
+ regs->pc -= 4;
+ }
+ }
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ setup_frame(sig, ka, oldset, regs);
+
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 1;
+
+ if (try_to_freeze())
+ goto no_signal;
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else if (!oldset)
+ oldset = &current->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, 0);
+
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ handle_signal(signr, &info, &ka, oldset, regs);
+
+ /*
+ * If a signal was successfully delivered, the saved sigmask
+ * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
+ * flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+ return 1;
+ }
+
+no_signal:
+ /* Did we come from a system call? */
+ if (regs->syscall_nr >= 0) {
+ /* Restart the system call - no handlers present */
+ switch (regs->regs[REG_RET]) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ /* Decode Syscall # */
+ regs->regs[REG_RET] = regs->syscall_nr;
+ regs->pc -= 4;
+ break;
+
+ case -ERESTART_RESTARTBLOCK:
+ regs->regs[REG_RET] = __NR_restart_syscall;
+ regs->pc -= 4;
+ break;
+ }
+ }
+
+ /* No signal to deliver -- put the saved sigmask back */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+
+ return 0;
+}
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index d545a686a201..59cd2859ce9b 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -7,7 +7,6 @@
*
* Taken from i386 version.
*/
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -27,28 +26,7 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way Unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- int fd[2];
- int error;
-
- error = do_pipe(fd);
- if (!error) {
- regs->regs[1] = fd[1];
- return fd[0];
- }
- return error;
-}
-
unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
-
EXPORT_SYMBOL(shm_align_mask);
#ifdef CONFIG_MMU
@@ -140,7 +118,7 @@ full_search:
#endif /* CONFIG_MMU */
static inline long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
unsigned long flags, int fd, unsigned long pgoff)
{
int error = -EBADF;
@@ -195,12 +173,13 @@ asmlinkage int sys_ipc(uint call, int first, int second,
if (call <= SEMCTL)
switch (call) {
case SEMOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
+ return sys_semtimedop(first,
+ (struct sembuf __user *)ptr,
second, NULL);
case SEMTIMEDOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
- second,
- (const struct timespec __user *)fifth);
+ return sys_semtimedop(first,
+ (struct sembuf __user *)ptr, second,
+ (const struct timespec __user *)fifth);
case SEMGET:
return sys_semget (first, second, third);
case SEMCTL: {
@@ -215,25 +194,28 @@ asmlinkage int sys_ipc(uint call, int first, int second,
return -EINVAL;
}
- if (call <= MSGCTL)
+ if (call <= MSGCTL)
switch (call) {
case MSGSND:
- return sys_msgsnd (first, (struct msgbuf __user *) ptr,
+ return sys_msgsnd (first, (struct msgbuf __user *) ptr,
second, third);
case MSGRCV:
switch (version) {
- case 0: {
+ case 0:
+ {
struct ipc_kludge tmp;
+
if (!ptr)
return -EINVAL;
-
+
if (copy_from_user(&tmp,
- (struct ipc_kludge __user *) ptr,
+ (struct ipc_kludge __user *) ptr,
sizeof (tmp)))
return -EFAULT;
+
return sys_msgrcv (first, tmp.msgp, second,
tmp.msgtyp, third);
- }
+ }
default:
return sys_msgrcv (first,
(struct msgbuf __user *) ptr,
@@ -247,7 +229,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
default:
return -EINVAL;
}
- if (call <= SHMCTL)
+ if (call <= SHMCTL)
switch (call) {
case SHMAT:
switch (version) {
@@ -265,7 +247,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
return do_shmat (first, (char __user *) ptr,
second, (ulong *) third);
}
- case SHMDT:
+ case SHMDT:
return sys_shmdt ((char __user *)ptr);
case SHMGET:
return sys_shmget (first, second, third);
@@ -275,7 +257,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
default:
return -EINVAL;
}
-
+
return -EINVAL;
}
@@ -289,49 +271,3 @@ asmlinkage int sys_uname(struct old_utsname * name)
up_read(&uts_sem);
return err?-EFAULT:0;
}
-
-asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
- size_t count, long dummy, loff_t pos)
-{
- return sys_pread64(fd, buf, count, pos);
-}
-
-asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
- size_t count, long dummy, loff_t pos)
-{
- return sys_pwrite64(fd, buf, count, pos);
-}
-
-asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
- u32 len0, u32 len1, int advice)
-{
-#ifdef __LITTLE_ENDIAN__
- return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
- (u64)len1 << 32 | len0, advice);
-#else
- return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
- (u64)len0 << 32 | len1, advice);
-#endif
-}
-
-#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
-#define SYSCALL_ARG3 "trapa #0x23"
-#else
-#define SYSCALL_ARG3 "trapa #0x13"
-#endif
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
-{
- register long __sc0 __asm__ ("r3") = __NR_execve;
- register long __sc4 __asm__ ("r4") = (long) filename;
- register long __sc5 __asm__ ("r5") = (long) argv;
- register long __sc6 __asm__ ("r6") = (long) envp;
- __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
- : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
- : "memory");
- return __sc0;
-}
diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c
new file mode 100644
index 000000000000..125e493ead82
--- /dev/null
+++ b/arch/sh/kernel/sys_sh32.c
@@ -0,0 +1,84 @@
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/ipc.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ regs->regs[1] = fd[1];
+ return fd[0];
+ }
+ return error;
+}
+
+asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
+ size_t count, long dummy, loff_t pos)
+{
+ return sys_pread64(fd, buf, count, pos);
+}
+
+asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
+ size_t count, long dummy, loff_t pos)
+{
+ return sys_pwrite64(fd, buf, count, pos);
+}
+
+asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
+ u32 len0, u32 len1, int advice)
+{
+#ifdef __LITTLE_ENDIAN__
+ return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
+ (u64)len1 << 32 | len0, advice);
+#else
+ return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
+ (u64)len0 << 32 | len1, advice);
+#endif
+}
+
+#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#define SYSCALL_ARG3 "trapa #0x23"
+#else
+#define SYSCALL_ARG3 "trapa #0x13"
+#endif
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long __sc0 __asm__ ("r3") = __NR_execve;
+ register long __sc4 __asm__ ("r4") = (long) filename;
+ register long __sc5 __asm__ ("r5") = (long) argv;
+ register long __sc6 __asm__ ("r6") = (long) envp;
+ __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
+ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
+ : "memory");
+ return __sc0;
+}
diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c
new file mode 100644
index 000000000000..578004d71e02
--- /dev/null
+++ b/arch/sh/kernel/sys_sh64.c
@@ -0,0 +1,66 @@
+/*
+ * arch/sh/kernel/sys_sh64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/SH5
+ * platform.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/syscalls.h>
+#include <linux/ipc.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
+ register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
+ register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
+ register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
+ __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)"
+ : "=r" (__sc0)
+ : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
+ __asm__ __volatile__ ("!dummy %0 %1 %2 %3"
+ : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
+ return __sc0;
+}
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls_32.S
index 10bec45415ba..10bec45415ba 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls_32.S
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
new file mode 100644
index 000000000000..98a93efe3691
--- /dev/null
+++ b/arch/sh/kernel/syscalls_64.S
@@ -0,0 +1,381 @@
+/*
+ * arch/sh/kernel/syscalls_64.S
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2004 - 2007 Paul Mundt
+ * Copyright (C) 2003, 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sys.h>
+
+ .section .data, "aw"
+ .balign 32
+
+/*
+ * System calls jump table
+ */
+ .globl sys_call_table
+sys_call_table:
+ .long sys_restart_syscall /* 0 - old "setup()" system call */
+ .long sys_exit
+ .long sys_fork
+ .long sys_read
+ .long sys_write
+ .long sys_open /* 5 */
+ .long sys_close
+ .long sys_waitpid
+ .long sys_creat
+ .long sys_link
+ .long sys_unlink /* 10 */
+ .long sys_execve
+ .long sys_chdir
+ .long sys_time
+ .long sys_mknod
+ .long sys_chmod /* 15 */
+ .long sys_lchown16
+ .long sys_ni_syscall /* old break syscall holder */
+ .long sys_stat
+ .long sys_lseek
+ .long sys_getpid /* 20 */
+ .long sys_mount
+ .long sys_oldumount
+ .long sys_setuid16
+ .long sys_getuid16
+ .long sys_stime /* 25 */
+ .long sh64_ptrace
+ .long sys_alarm
+ .long sys_fstat
+ .long sys_pause
+ .long sys_utime /* 30 */
+ .long sys_ni_syscall /* old stty syscall holder */
+ .long sys_ni_syscall /* old gtty syscall holder */
+ .long sys_access
+ .long sys_nice
+ .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+ .long sys_sync
+ .long sys_kill
+ .long sys_rename
+ .long sys_mkdir
+ .long sys_rmdir /* 40 */
+ .long sys_dup
+ .long sys_pipe
+ .long sys_times
+ .long sys_ni_syscall /* old prof syscall holder */
+ .long sys_brk /* 45 */
+ .long sys_setgid16
+ .long sys_getgid16
+ .long sys_signal
+ .long sys_geteuid16
+ .long sys_getegid16 /* 50 */
+ .long sys_acct
+ .long sys_umount /* recycled never used phys( */
+ .long sys_ni_syscall /* old lock syscall holder */
+ .long sys_ioctl
+ .long sys_fcntl /* 55 */
+ .long sys_ni_syscall /* old mpx syscall holder */
+ .long sys_setpgid
+ .long sys_ni_syscall /* old ulimit syscall holder */
+ .long sys_ni_syscall /* sys_olduname */
+ .long sys_umask /* 60 */
+ .long sys_chroot
+ .long sys_ustat
+ .long sys_dup2
+ .long sys_getppid
+ .long sys_getpgrp /* 65 */
+ .long sys_setsid
+ .long sys_sigaction
+ .long sys_sgetmask
+ .long sys_ssetmask
+ .long sys_setreuid16 /* 70 */
+ .long sys_setregid16
+ .long sys_sigsuspend
+ .long sys_sigpending
+ .long sys_sethostname
+ .long sys_setrlimit /* 75 */
+ .long sys_old_getrlimit
+ .long sys_getrusage
+ .long sys_gettimeofday
+ .long sys_settimeofday
+ .long sys_getgroups16 /* 80 */
+ .long sys_setgroups16
+ .long sys_ni_syscall /* sys_oldselect */
+ .long sys_symlink
+ .long sys_lstat
+ .long sys_readlink /* 85 */
+ .long sys_uselib
+ .long sys_swapon
+ .long sys_reboot
+ .long old_readdir
+ .long old_mmap /* 90 */
+ .long sys_munmap
+ .long sys_truncate
+ .long sys_ftruncate
+ .long sys_fchmod
+ .long sys_fchown16 /* 95 */
+ .long sys_getpriority
+ .long sys_setpriority
+ .long sys_ni_syscall /* old profil syscall holder */
+ .long sys_statfs
+ .long sys_fstatfs /* 100 */
+ .long sys_ni_syscall /* ioperm */
+ .long sys_socketcall /* Obsolete implementation of socket syscall */
+ .long sys_syslog
+ .long sys_setitimer
+ .long sys_getitimer /* 105 */
+ .long sys_newstat
+ .long sys_newlstat
+ .long sys_newfstat
+ .long sys_uname
+ .long sys_ni_syscall /* 110 */ /* iopl */
+ .long sys_vhangup
+ .long sys_ni_syscall /* idle */
+ .long sys_ni_syscall /* vm86old */
+ .long sys_wait4
+ .long sys_swapoff /* 115 */
+ .long sys_sysinfo
+ .long sys_ipc /* Obsolete ipc syscall implementation */
+ .long sys_fsync
+ .long sys_sigreturn
+ .long sys_clone /* 120 */
+ .long sys_setdomainname
+ .long sys_newuname
+ .long sys_ni_syscall /* sys_modify_ldt */
+ .long sys_adjtimex
+ .long sys_mprotect /* 125 */
+ .long sys_sigprocmask
+ .long sys_ni_syscall /* old "create_module" */
+ .long sys_init_module
+ .long sys_delete_module
+ .long sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long sys_quotactl
+ .long sys_getpgid
+ .long sys_fchdir
+ .long sys_bdflush
+ .long sys_sysfs /* 135 */
+ .long sys_personality
+ .long sys_ni_syscall /* for afs_syscall */
+ .long sys_setfsuid16
+ .long sys_setfsgid16
+ .long sys_llseek /* 140 */
+ .long sys_getdents
+ .long sys_select
+ .long sys_flock
+ .long sys_msync
+ .long sys_readv /* 145 */
+ .long sys_writev
+ .long sys_getsid
+ .long sys_fdatasync
+ .long sys_sysctl
+ .long sys_mlock /* 150 */
+ .long sys_munlock
+ .long sys_mlockall
+ .long sys_munlockall
+ .long sys_sched_setparam
+ .long sys_sched_getparam /* 155 */
+ .long sys_sched_setscheduler
+ .long sys_sched_getscheduler
+ .long sys_sched_yield
+ .long sys_sched_get_priority_max
+ .long sys_sched_get_priority_min /* 160 */
+ .long sys_sched_rr_get_interval
+ .long sys_nanosleep
+ .long sys_mremap
+ .long sys_setresuid16
+ .long sys_getresuid16 /* 165 */
+ .long sys_ni_syscall /* vm86 */
+ .long sys_ni_syscall /* old "query_module" */
+ .long sys_poll
+ .long sys_nfsservctl
+ .long sys_setresgid16 /* 170 */
+ .long sys_getresgid16
+ .long sys_prctl
+ .long sys_rt_sigreturn
+ .long sys_rt_sigaction
+ .long sys_rt_sigprocmask /* 175 */
+ .long sys_rt_sigpending
+ .long sys_rt_sigtimedwait
+ .long sys_rt_sigqueueinfo
+ .long sys_rt_sigsuspend
+ .long sys_pread64 /* 180 */
+ .long sys_pwrite64
+ .long sys_chown16
+ .long sys_getcwd
+ .long sys_capget
+ .long sys_capset /* 185 */
+ .long sys_sigaltstack
+ .long sys_sendfile
+ .long sys_ni_syscall /* streams1 */
+ .long sys_ni_syscall /* streams2 */
+ .long sys_vfork /* 190 */
+ .long sys_getrlimit
+ .long sys_mmap2
+ .long sys_truncate64
+ .long sys_ftruncate64
+ .long sys_stat64 /* 195 */
+ .long sys_lstat64
+ .long sys_fstat64
+ .long sys_lchown
+ .long sys_getuid
+ .long sys_getgid /* 200 */
+ .long sys_geteuid
+ .long sys_getegid
+ .long sys_setreuid
+ .long sys_setregid
+ .long sys_getgroups /* 205 */
+ .long sys_setgroups
+ .long sys_fchown
+ .long sys_setresuid
+ .long sys_getresuid
+ .long sys_setresgid /* 210 */
+ .long sys_getresgid
+ .long sys_chown
+ .long sys_setuid
+ .long sys_setgid
+ .long sys_setfsuid /* 215 */
+ .long sys_setfsgid
+ .long sys_pivot_root
+ .long sys_mincore
+ .long sys_madvise
+ /* Broken-out socket family (maintain backwards compatibility in syscall
+ numbering with 2.4) */
+ .long sys_socket /* 220 */
+ .long sys_bind
+ .long sys_connect
+ .long sys_listen
+ .long sys_accept
+ .long sys_getsockname /* 225 */
+ .long sys_getpeername
+ .long sys_socketpair
+ .long sys_send
+ .long sys_sendto
+ .long sys_recv /* 230*/
+ .long sys_recvfrom
+ .long sys_shutdown
+ .long sys_setsockopt
+ .long sys_getsockopt
+ .long sys_sendmsg /* 235 */
+ .long sys_recvmsg
+ /* Broken-out IPC family (maintain backwards compatibility in syscall
+ numbering with 2.4) */
+ .long sys_semop
+ .long sys_semget
+ .long sys_semctl
+ .long sys_msgsnd /* 240 */
+ .long sys_msgrcv
+ .long sys_msgget
+ .long sys_msgctl
+ .long sys_shmat
+ .long sys_shmdt /* 245 */
+ .long sys_shmget
+ .long sys_shmctl
+ /* Rest of syscalls listed in 2.4 i386 unistd.h */
+ .long sys_getdents64
+ .long sys_fcntl64
+ .long sys_ni_syscall /* 250 reserved for TUX */
+ .long sys_ni_syscall /* Reserved for Security */
+ .long sys_gettid
+ .long sys_readahead
+ .long sys_setxattr
+ .long sys_lsetxattr /* 255 */
+ .long sys_fsetxattr
+ .long sys_getxattr
+ .long sys_lgetxattr
+ .long sys_fgetxattr
+ .long sys_listxattr /* 260 */
+ .long sys_llistxattr
+ .long sys_flistxattr
+ .long sys_removexattr
+ .long sys_lremovexattr
+ .long sys_fremovexattr /* 265 */
+ .long sys_tkill
+ .long sys_sendfile64
+ .long sys_futex
+ .long sys_sched_setaffinity
+ .long sys_sched_getaffinity /* 270 */
+ .long sys_ni_syscall
+ .long sys_ni_syscall
+ .long sys_io_setup
+ .long sys_io_destroy
+ .long sys_io_getevents /* 275 */
+ .long sys_io_submit
+ .long sys_io_cancel
+ .long sys_fadvise64
+ .long sys_ni_syscall
+ .long sys_exit_group /* 280 */
+ /* Rest of new 2.6 syscalls */
+ .long sys_lookup_dcookie
+ .long sys_epoll_create
+ .long sys_epoll_ctl
+ .long sys_epoll_wait
+ .long sys_remap_file_pages /* 285 */
+ .long sys_set_tid_address
+ .long sys_timer_create
+ .long sys_timer_settime
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun /* 290 */
+ .long sys_timer_delete
+ .long sys_clock_settime
+ .long sys_clock_gettime
+ .long sys_clock_getres
+ .long sys_clock_nanosleep /* 295 */
+ .long sys_statfs64
+ .long sys_fstatfs64
+ .long sys_tgkill
+ .long sys_utimes
+ .long sys_fadvise64_64 /* 300 */
+ .long sys_ni_syscall /* Reserved for vserver */
+ .long sys_ni_syscall /* Reserved for mbind */
+ .long sys_ni_syscall /* get_mempolicy */
+ .long sys_ni_syscall /* set_mempolicy */
+ .long sys_mq_open /* 305 */
+ .long sys_mq_unlink
+ .long sys_mq_timedsend
+ .long sys_mq_timedreceive
+ .long sys_mq_notify
+ .long sys_mq_getsetattr /* 310 */
+ .long sys_ni_syscall /* Reserved for kexec */
+ .long sys_waitid
+ .long sys_add_key
+ .long sys_request_key
+ .long sys_keyctl /* 315 */
+ .long sys_ioprio_set
+ .long sys_ioprio_get
+ .long sys_inotify_init
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch /* 320 */
+ .long sys_ni_syscall
+ .long sys_migrate_pages
+ .long sys_openat
+ .long sys_mkdirat
+ .long sys_mknodat /* 325 */
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64
+ .long sys_unlinkat
+ .long sys_renameat /* 330 */
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat
+ .long sys_fchmodat
+ .long sys_faccessat /* 335 */
+ .long sys_pselect6
+ .long sys_ppoll
+ .long sys_unshare
+ .long sys_set_robust_list
+ .long sys_get_robust_list /* 340 */
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee
+ .long sys_vmsplice
+ .long sys_move_pages /* 345 */
+ .long sys_getcpu
+ .long sys_epoll_pwait
+ .long sys_utimensat
+ .long sys_signalfd
+ .long sys_timerfd /* 350 */
+ .long sys_eventfd
+ .long sys_fallocate
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time_32.c
index 2bc04bfee738..2bc04bfee738 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time_32.c
diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c
new file mode 100644
index 000000000000..f819ba38a6ce
--- /dev/null
+++ b/arch/sh/kernel/time_64.c
@@ -0,0 +1,519 @@
+/*
+ * arch/sh/kernel/time_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ * Copyright (C) 2003 Richard Curnow
+ *
+ * Original TMU/RTC code taken from sh version.
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ * Some code taken from i386 version.
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/bcd.h>
+#include <linux/timex.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/cpu/registers.h> /* required by inline __asm__ stmt. */
+#include <asm/cpu/irq.h>
+#include <asm/addrspace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#define TMU_TOCR_INIT 0x00
+#define TMU0_TCR_INIT 0x0020
+#define TMU_TSTR_INIT 1
+#define TMU_TSTR_OFF 0
+
+/* Real Time Clock */
+#define RTC_BLOCK_OFF 0x01040000
+#define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
+#define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */
+#define RTC_RCR1 (rtc_base + 0x38)
+
+/* Clock, Power and Reset Controller */
+#define CPRC_BLOCK_OFF 0x01010000
+#define CPRC_BASE PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF
+
+#define FRQCR (cprc_base+0x0)
+#define WTCSR (cprc_base+0x0018)
+#define STBCR (cprc_base+0x0030)
+
+/* Time Management Unit */
+#define TMU_BLOCK_OFF 0x01020000
+#define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
+#define TMU0_BASE tmu_base + 0x8 + (0xc * 0x0)
+#define TMU1_BASE tmu_base + 0x8 + (0xc * 0x1)
+#define TMU2_BASE tmu_base + 0x8 + (0xc * 0x2)
+
+#define TMU_TOCR tmu_base+0x0 /* Byte access */
+#define TMU_TSTR tmu_base+0x4 /* Byte access */
+
+#define TMU0_TCOR TMU0_BASE+0x0 /* Long access */
+#define TMU0_TCNT TMU0_BASE+0x4 /* Long access */
+#define TMU0_TCR TMU0_BASE+0x8 /* Word access */
+
+#define TICK_SIZE (tick_nsec / 1000)
+
+static unsigned long tmu_base, rtc_base;
+unsigned long cprc_base;
+
+/* Variables to allow interpolation of time of day to resolution better than a
+ * jiffy. */
+
+/* This is effectively protected by xtime_lock */
+static unsigned long ctc_last_interrupt;
+static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */
+
+#define CTC_JIFFY_SCALE_SHIFT 40
+
+/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */
+static unsigned long long scaled_recip_ctc_ticks_per_jiffy;
+
+/* Estimate number of microseconds that have elapsed since the last timer tick,
+ by scaling the delta that has occurred in the CTC register.
+
+ WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at
+ the CPU clock rate. If the CPU sleeps, the CTC stops counting. Bear this
+ in mind if enabling SLEEP_WORKS in process.c. In that case, this algorithm
+ probably needs to use TMU.TCNT0 instead. This will work even if the CPU is
+ sleeping, though will be coarser.
+
+ FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime
+ is running or if the freq or tick arguments of adjtimex are modified after
+ we have calibrated the scaling factor? This will result in either a jump at
+ the end of a tick period, or a wrap backwards at the start of the next one,
+ if the application is reading the time of day often enough. I think we
+ ought to do better than this. For this reason, usecs_per_jiffy is left
+ separated out in the calculation below. This allows some future hook into
+ the adjtime-related stuff in kernel/timer.c to remove this hazard.
+
+*/
+
+static unsigned long usecs_since_tick(void)
+{
+ unsigned long long current_ctc;
+ long ctc_ticks_since_interrupt;
+ unsigned long long ull_ctc_ticks_since_interrupt;
+ unsigned long result;
+
+ unsigned long long mul1_out;
+ unsigned long long mul1_out_high;
+ unsigned long long mul2_out_low, mul2_out_high;
+
+ /* Read CTC register */
+ asm ("getcon cr62, %0" : "=r" (current_ctc));
+ /* Note, the CTC counts down on each CPU clock, not up.
+ Note(2), use long type to get correct wraparound arithmetic when
+ the counter crosses zero. */
+ ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc;
+ ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt;
+
+ /* Inline assembly to do 32x32x32->64 multiplier */
+ asm volatile ("mulu.l %1, %2, %0" :
+ "=r" (mul1_out) :
+ "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy));
+
+ mul1_out_high = mul1_out >> 32;
+
+ asm volatile ("mulu.l %1, %2, %0" :
+ "=r" (mul2_out_low) :
+ "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy));
+
+#if 1
+ asm volatile ("mulu.l %1, %2, %0" :
+ "=r" (mul2_out_high) :
+ "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy));
+#endif
+
+ result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT);
+
+ return result;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ unsigned long seq;
+ unsigned long usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = usecs_since_tick();
+ sec = xtime.tv_sec;
+ usec += xtime.tv_nsec / 1000;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+}
+
+int do_settimeofday(struct timespec *tv)
+{
+ time_t wtm_sec, sec = tv->tv_sec;
+ long wtm_nsec, nsec = tv->tv_nsec;
+
+ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+
+ write_seqlock_irq(&xtime_lock);
+ /*
+ * This is revolting. We need to set "xtime" correctly. However, the
+ * value in this location is the value at the most recent update of
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+ nsec -= 1000 * usecs_since_tick();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+ set_normalized_timespec(&xtime, sec, nsec);
+ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+ ntp_clear();
+ write_sequnlock_irq(&xtime_lock);
+ clock_was_set();
+
+ return 0;
+}
+EXPORT_SYMBOL(do_settimeofday);
+
+/* Dummy RTC ops */
+static void null_rtc_get_time(struct timespec *tv)
+{
+ tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+ tv->tv_nsec = 0;
+}
+
+static int null_rtc_set_time(const time_t secs)
+{
+ return 0;
+}
+
+void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
+int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
+
+/* last time the RTC clock got updated */
+static long last_rtc_update;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void do_timer_interrupt(void)
+{
+ unsigned long long current_ctc;
+ asm ("getcon cr62, %0" : "=r" (current_ctc));
+ ctc_last_interrupt = (unsigned long) current_ctc;
+
+ do_timer(1);
+#ifndef CONFIG_SMP
+ update_process_times(user_mode(get_irq_regs()));
+#endif
+ if (current->pid)
+ profile_tick(CPU_PROFILING);
+
+#ifdef CONFIG_HEARTBEAT
+ if (sh_mv.mv_heartbeat != NULL)
+ sh_mv.mv_heartbeat();
+#endif
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if (ntp_synced() &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+ (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+ if (rtc_sh_set_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 600;
+ }
+}
+
+/*
+ * This is the same as the above, except we _also_ save the current
+ * Time Stamp Counter value at the time of the timer interrupt, so that
+ * we later on can estimate the time of day more exactly.
+ */
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ unsigned long timer_status;
+
+ /* Clear UNF bit */
+ timer_status = ctrl_inw(TMU0_TCR);
+ timer_status &= ~0x100;
+ ctrl_outw(timer_status, TMU0_TCR);
+
+ /*
+ * Here we are in the timer irq handler. We just have irqs locally
+ * disabled but we don't know if the timer_bh is running on the other
+ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+ * the irq version of write_lock because as just said we have irq
+ * locally disabled. -arca
+ */
+ write_lock(&xtime_lock);
+ do_timer_interrupt();
+ write_unlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+
+static __init unsigned int get_cpu_hz(void)
+{
+ unsigned int count;
+ unsigned long __dummy;
+ unsigned long ctc_val_init, ctc_val;
+
+ /*
+ ** Regardless the toolchain, force the compiler to use the
+ ** arbitrary register r3 as a clock tick counter.
+ ** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
+ */
+ register unsigned long long __rtc_irq_flag __asm__ ("r3");
+
+ local_irq_enable();
+ do {} while (ctrl_inb(rtc_base) != 0);
+ ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */
+
+ /*
+ * r3 is arbitrary. CDC does not support "=z".
+ */
+ ctc_val_init = 0xffffffff;
+ ctc_val = ctc_val_init;
+
+ asm volatile("gettr tr0, %1\n\t"
+ "putcon %0, " __CTC "\n\t"
+ "and %2, r63, %2\n\t"
+ "pta $+4, tr0\n\t"
+ "beq/l %2, r63, tr0\n\t"
+ "ptabs %1, tr0\n\t"
+ "getcon " __CTC ", %0\n\t"
+ : "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
+ : "0" (0));
+ local_irq_disable();
+ /*
+ * SH-3:
+ * CPU clock = 4 stages * loop
+ * tst rm,rm if id ex
+ * bt/s 1b if id ex
+ * add #1,rd if id ex
+ * (if) pipe line stole
+ * tst rm,rm if id ex
+ * ....
+ *
+ *
+ * SH-4:
+ * CPU clock = 6 stages * loop
+ * I don't know why.
+ * ....
+ *
+ * SH-5:
+ * Use CTC register to count. This approach returns the right value
+ * even if the I-cache is disabled (e.g. whilst debugging.)
+ *
+ */
+
+ count = ctc_val_init - ctc_val; /* CTC counts down */
+
+ /*
+ * This really is count by the number of clock cycles
+ * by the ratio between a complete R64CNT
+ * wrap-around (128) and CUI interrupt being raised (64).
+ */
+ return count*2;
+}
+
+static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
+{
+ struct pt_regs *regs = get_irq_regs();
+
+ ctrl_outb(0, RTC_RCR1); /* Disable Carry Interrupts */
+ regs->regs[3] = 1; /* Using r3 */
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction irq0 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "timer",
+};
+static struct irqaction irq1 = {
+ .handler = sh64_rtc_interrupt,
+ .flags = IRQF_DISABLED,
+ .mask = CPU_MASK_NONE,
+ .name = "rtc",
+};
+
+void __init time_init(void)
+{
+ unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+ unsigned long interval;
+ unsigned long frqcr, ifc, pfc;
+ static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
+#define bfc_table ifc_table /* Same */
+#define pfc_table ifc_table /* Same */
+
+ tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
+ if (!tmu_base) {
+ panic("Unable to remap TMU\n");
+ }
+
+ rtc_base = onchip_remap(RTC_BASE, 1024, "RTC");
+ if (!rtc_base) {
+ panic("Unable to remap RTC\n");
+ }
+
+ cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
+ if (!cprc_base) {
+ panic("Unable to remap CPRC\n");
+ }
+
+ rtc_sh_get_time(&xtime);
+
+ setup_irq(TIMER_IRQ, &irq0);
+ setup_irq(RTC_IRQ, &irq1);
+
+ /* Check how fast it is.. */
+ cpu_clock = get_cpu_hz();
+
+ /* Note careful order of operations to maintain reasonable precision and avoid overflow. */
+ scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));
+
+ free_irq(RTC_IRQ, NULL);
+
+ printk("CPU clock: %d.%02dMHz\n",
+ (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
+ {
+ unsigned short bfc;
+ frqcr = ctrl_inl(FRQCR);
+ ifc = ifc_table[(frqcr>> 6) & 0x0007];
+ bfc = bfc_table[(frqcr>> 3) & 0x0007];
+ pfc = pfc_table[(frqcr>> 12) & 0x0007];
+ master_clock = cpu_clock * ifc;
+ bus_clock = master_clock/bfc;
+ }
+
+ printk("Bus clock: %d.%02dMHz\n",
+ (bus_clock/1000000), (bus_clock % 1000000)/10000);
+ module_clock = master_clock/pfc;
+ printk("Module clock: %d.%02dMHz\n",
+ (module_clock/1000000), (module_clock % 1000000)/10000);
+ interval = (module_clock/(HZ*4));
+
+ printk("Interval = %ld\n", interval);
+
+ current_cpu_data.cpu_clock = cpu_clock;
+ current_cpu_data.master_clock = master_clock;
+ current_cpu_data.bus_clock = bus_clock;
+ current_cpu_data.module_clock = module_clock;
+
+ /* Start TMU0 */
+ ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
+ ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+ ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+ ctrl_outl(interval, TMU0_TCOR);
+ ctrl_outl(interval, TMU0_TCNT);
+ ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+}
+
+void enter_deep_standby(void)
+{
+ /* Disable watchdog timer */
+ ctrl_outl(0xa5000000, WTCSR);
+ /* Configure deep standby on sleep */
+ ctrl_outl(0x03, STBCR);
+
+#ifdef CONFIG_SH_ALPHANUMERIC
+ {
+ extern void mach_alphanum(int position, unsigned char value);
+ extern void mach_alphanum_brightness(int setting);
+ char halted[] = "Halted. ";
+ int i;
+ mach_alphanum_brightness(6); /* dimmest setting above off */
+ for (i=0; i<8; i++) {
+ mach_alphanum(i, halted[i]);
+ }
+ asm __volatile__ ("synco");
+ }
+#endif
+
+ asm __volatile__ ("sleep");
+ asm __volatile__ ("synci");
+ asm __volatile__ ("nop");
+ asm __volatile__ ("nop");
+ asm __volatile__ ("nop");
+ asm __volatile__ ("nop");
+ panic("Unexpected wakeup!\n");
+}
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ /* RTC base, filled in by rtc_init */
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = IRQ_PRI,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = IRQ_CUI,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = IRQ_ATI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static int __init rtc_init(void)
+{
+ rtc_resources[0].start = rtc_base;
+ rtc_resources[0].end = rtc_resources[0].start + 0x58 - 1;
+
+ return platform_device_register(&rtc_device);
+}
+device_initcall(rtc_init);
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
index 82de6895ade5..499e07beebe2 100644
--- a/arch/sh/kernel/timers/timer-cmt.c
+++ b/arch/sh/kernel/timers/timer-cmt.c
@@ -31,7 +31,9 @@
#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
#define CMT_CMCSR_INIT 0x0040
#define CMT_CMCSR_CALIB 0x0000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7263)
#define CMT_CMSTR 0xfffec000
#define CMT_CMCSR_0 0xfffec002
#define CMT_CMCNT_0 0xfffec004
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 628ec9a15e38..8935570008d2 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -174,6 +174,7 @@ static int tmu_timer_init(void)
tmu_timer_stop();
#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7721) && \
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \
!defined(CONFIG_CPU_SUBTYPE_SH7785) && \
!defined(CONFIG_CPU_SUBTYPE_SHX3)
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index cf99111cb33f..a3bdc68ef02c 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -1,947 +1,68 @@
-/*
- * 'traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
- *
- * SuperH version: Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2000 Philipp Rumpf
- * Copyright (C) 2000 David Howells
- * Copyright (C) 2002 - 2007 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/io.h>
#include <linux/bug.h>
-#include <linux/debug_locks.h>
+#include <linux/io.h>
+#include <linux/types.h>
#include <linux/kdebug.h>
-#include <linux/kexec.h>
-#include <linux/limits.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#define CHK_REMOTE_DEBUG(regs) \
-{ \
- if (kgdb_debug_hook && !user_mode(regs))\
- (*kgdb_debug_hook)(regs); \
-}
-#else
-#define CHK_REMOTE_DEBUG(regs)
-#endif
-
-#ifdef CONFIG_CPU_SH2
-# define TRAP_RESERVED_INST 4
-# define TRAP_ILLEGAL_SLOT_INST 6
-# define TRAP_ADDRESS_ERROR 9
-# ifdef CONFIG_CPU_SH2A
-# define TRAP_DIVZERO_ERROR 17
-# define TRAP_DIVOVF_ERROR 18
-# endif
-#else
-#define TRAP_RESERVED_INST 12
-#define TRAP_ILLEGAL_SLOT_INST 13
-#endif
-
-static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
-{
- unsigned long p;
- int i;
-
- printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
-
- for (p = bottom & ~31; p < top; ) {
- printk("%04lx: ", p & 0xffff);
-
- for (i = 0; i < 8; i++, p += 4) {
- unsigned int val;
-
- if (p < bottom || p >= top)
- printk(" ");
- else {
- if (__get_user(val, (unsigned int __user *)p)) {
- printk("\n");
- return;
- }
- printk("%08x ", val);
- }
- }
- printk("\n");
- }
-}
-
-static DEFINE_SPINLOCK(die_lock);
-
-void die(const char * str, struct pt_regs * regs, long err)
-{
- static int die_counter;
-
- oops_enter();
-
- console_verbose();
- spin_lock_irq(&die_lock);
- bust_spinlocks(1);
-
- printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-
- CHK_REMOTE_DEBUG(regs);
- print_modules();
- show_regs(regs);
-
- printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
- task_pid_nr(current), task_stack_page(current) + 1);
-
- if (!user_mode(regs) || in_interrupt())
- dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
- (unsigned long)task_stack_page(current));
-
- bust_spinlocks(0);
- add_taint(TAINT_DIE);
- spin_unlock_irq(&die_lock);
-
- if (kexec_should_crash(current))
- crash_kexec(regs);
-
- if (in_interrupt())
- panic("Fatal exception in interrupt");
-
- if (panic_on_oops)
- panic("Fatal exception");
-
- oops_exit();
- do_exit(SIGSEGV);
-}
-
-static inline void die_if_kernel(const char *str, struct pt_regs *regs,
- long err)
-{
- if (!user_mode(regs))
- die(str, regs, err);
-}
-
-/*
- * try and fix up kernelspace address errors
- * - userspace errors just cause EFAULT to be returned, resulting in SEGV
- * - kernel/userspace interfaces cause a jump to an appropriate handler
- * - other kernel errors are bad
- * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
- */
-static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
-{
- if (!user_mode(regs)) {
- const struct exception_table_entry *fixup;
- fixup = search_exception_tables(regs->pc);
- if (fixup) {
- regs->pc = fixup->fixup;
- return 0;
- }
- die(str, regs, err);
- }
- return -EFAULT;
-}
-
-/*
- * handle an instruction that does an unaligned memory access by emulating the
- * desired behaviour
- * - note that PC _may not_ point to the faulting instruction
- * (if that instruction is in a branch delay slot)
- * - return 0 if emulation okay, -EFAULT on existential error
- */
-static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
-{
- int ret, index, count;
- unsigned long *rm, *rn;
- unsigned char *src, *dst;
-
- index = (instruction>>8)&15; /* 0x0F00 */
- rn = &regs->regs[index];
-
- index = (instruction>>4)&15; /* 0x00F0 */
- rm = &regs->regs[index];
-
- count = 1<<(instruction&3);
-
- ret = -EFAULT;
- switch (instruction>>12) {
- case 0: /* mov.[bwl] to/from memory via r0+rn */
- if (instruction & 8) {
- /* from memory */
- src = (unsigned char*) *rm;
- src += regs->regs[0];
- dst = (unsigned char*) rn;
- *(unsigned long*)dst = 0;
-
-#ifdef __LITTLE_ENDIAN__
- if (copy_from_user(dst, src, count))
- goto fetch_fault;
-
- if ((count == 2) && dst[1] & 0x80) {
- dst[2] = 0xff;
- dst[3] = 0xff;
- }
-#else
- dst += 4-count;
-
- if (__copy_user(dst, src, count))
- goto fetch_fault;
-
- if ((count == 2) && dst[2] & 0x80) {
- dst[0] = 0xff;
- dst[1] = 0xff;
- }
-#endif
- } else {
- /* to memory */
- src = (unsigned char*) rm;
-#if !defined(__LITTLE_ENDIAN__)
- src += 4-count;
-#endif
- dst = (unsigned char*) *rn;
- dst += regs->regs[0];
-
- if (copy_to_user(dst, src, count))
- goto fetch_fault;
- }
- ret = 0;
- break;
-
- case 1: /* mov.l Rm,@(disp,Rn) */
- src = (unsigned char*) rm;
- dst = (unsigned char*) *rn;
- dst += (instruction&0x000F)<<2;
-
- if (copy_to_user(dst,src,4))
- goto fetch_fault;
- ret = 0;
- break;
-
- case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
- if (instruction & 4)
- *rn -= count;
- src = (unsigned char*) rm;
- dst = (unsigned char*) *rn;
-#if !defined(__LITTLE_ENDIAN__)
- src += 4-count;
-#endif
- if (copy_to_user(dst, src, count))
- goto fetch_fault;
- ret = 0;
- break;
-
- case 5: /* mov.l @(disp,Rm),Rn */
- src = (unsigned char*) *rm;
- src += (instruction&0x000F)<<2;
- dst = (unsigned char*) rn;
- *(unsigned long*)dst = 0;
-
- if (copy_from_user(dst,src,4))
- goto fetch_fault;
- ret = 0;
- break;
- case 6: /* mov.[bwl] from memory, possibly with post-increment */
- src = (unsigned char*) *rm;
- if (instruction & 4)
- *rm += count;
- dst = (unsigned char*) rn;
- *(unsigned long*)dst = 0;
-
-#ifdef __LITTLE_ENDIAN__
- if (copy_from_user(dst, src, count))
- goto fetch_fault;
-
- if ((count == 2) && dst[1] & 0x80) {
- dst[2] = 0xff;
- dst[3] = 0xff;
- }
-#else
- dst += 4-count;
-
- if (copy_from_user(dst, src, count))
- goto fetch_fault;
-
- if ((count == 2) && dst[2] & 0x80) {
- dst[0] = 0xff;
- dst[1] = 0xff;
- }
-#endif
- ret = 0;
- break;
-
- case 8:
- switch ((instruction&0xFF00)>>8) {
- case 0x81: /* mov.w R0,@(disp,Rn) */
- src = (unsigned char*) &regs->regs[0];
-#if !defined(__LITTLE_ENDIAN__)
- src += 2;
-#endif
- dst = (unsigned char*) *rm; /* called Rn in the spec */
- dst += (instruction&0x000F)<<1;
-
- if (copy_to_user(dst, src, 2))
- goto fetch_fault;
- ret = 0;
- break;
-
- case 0x85: /* mov.w @(disp,Rm),R0 */
- src = (unsigned char*) *rm;
- src += (instruction&0x000F)<<1;
- dst = (unsigned char*) &regs->regs[0];
- *(unsigned long*)dst = 0;
-
-#if !defined(__LITTLE_ENDIAN__)
- dst += 2;
-#endif
-
- if (copy_from_user(dst, src, 2))
- goto fetch_fault;
-
-#ifdef __LITTLE_ENDIAN__
- if (dst[1] & 0x80) {
- dst[2] = 0xff;
- dst[3] = 0xff;
- }
-#else
- if (dst[2] & 0x80) {
- dst[0] = 0xff;
- dst[1] = 0xff;
- }
-#endif
- ret = 0;
- break;
- }
- break;
- }
- return ret;
-
- fetch_fault:
- /* Argh. Address not only misaligned but also non-existent.
- * Raise an EFAULT and see if it's trapped
- */
- return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
-}
-
-/*
- * emulate the instruction in the delay slot
- * - fetches the instruction from PC+2
- */
-static inline int handle_unaligned_delayslot(struct pt_regs *regs)
+#ifdef CONFIG_BUG
+static void handle_BUG(struct pt_regs *regs)
{
- u16 instruction;
-
- if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
- /* the instruction-fetch faulted */
- if (user_mode(regs))
- return -EFAULT;
-
- /* kernel */
- die("delay-slot-insn faulting in handle_unaligned_delayslot",
- regs, 0);
+ enum bug_trap_type tt;
+ tt = report_bug(regs->pc, regs);
+ if (tt == BUG_TRAP_TYPE_WARN) {
+ regs->pc += instruction_size(regs->pc);
+ return;
}
- return handle_unaligned_ins(instruction,regs);
+ die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
}
-/*
- * handle an instruction that does an unaligned memory access
- * - have to be careful of branch delay-slot instructions that fault
- * SH3:
- * - if the branch would be taken PC points to the branch
- * - if the branch would not be taken, PC points to delay-slot
- * SH4:
- * - PC always points to delayed branch
- * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
- */
-
-/* Macros to determine offset from current PC for branch instructions */
-/* Explicit type coercion is used to force sign extension where needed */
-#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
-#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
-
-/*
- * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
- * opcodes..
- */
-#ifndef CONFIG_CPU_SH2A
-static int handle_unaligned_notify_count = 10;
-
-static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long addr)
{
- u_int rm;
- int ret, index;
-
- index = (instruction>>8)&15; /* 0x0F00 */
- rm = regs->regs[index];
-
- /* shout about the first ten userspace fixups */
- if (user_mode(regs) && handle_unaligned_notify_count>0) {
- handle_unaligned_notify_count--;
-
- printk(KERN_NOTICE "Fixing up unaligned userspace access "
- "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
- current->comm, task_pid_nr(current),
- (u16 *)regs->pc, instruction);
- }
-
- ret = -EFAULT;
- switch (instruction&0xF000) {
- case 0x0000:
- if (instruction==0x000B) {
- /* rts */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0)
- regs->pc = regs->pr;
- }
- else if ((instruction&0x00FF)==0x0023) {
- /* braf @Rm */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0)
- regs->pc += rm + 4;
- }
- else if ((instruction&0x00FF)==0x0003) {
- /* bsrf @Rm */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0) {
- regs->pr = regs->pc + 4;
- regs->pc += rm + 4;
- }
- }
- else {
- /* mov.[bwl] to/from memory via r0+rn */
- goto simple;
- }
- break;
-
- case 0x1000: /* mov.l Rm,@(disp,Rn) */
- goto simple;
-
- case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
- goto simple;
-
- case 0x4000:
- if ((instruction&0x00FF)==0x002B) {
- /* jmp @Rm */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0)
- regs->pc = rm;
- }
- else if ((instruction&0x00FF)==0x000B) {
- /* jsr @Rm */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0) {
- regs->pr = regs->pc + 4;
- regs->pc = rm;
- }
- }
- else {
- /* mov.[bwl] to/from memory via r0+rn */
- goto simple;
- }
- break;
-
- case 0x5000: /* mov.l @(disp,Rm),Rn */
- goto simple;
-
- case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
- goto simple;
-
- case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
- switch (instruction&0x0F00) {
- case 0x0100: /* mov.w R0,@(disp,Rm) */
- goto simple;
- case 0x0500: /* mov.w @(disp,Rm),R0 */
- goto simple;
- case 0x0B00: /* bf lab - no delayslot*/
- break;
- case 0x0F00: /* bf/s lab */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0) {
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
- if ((regs->sr & 0x00000001) != 0)
- regs->pc += 4; /* next after slot */
- else
-#endif
- regs->pc += SH_PC_8BIT_OFFSET(instruction);
- }
- break;
- case 0x0900: /* bt lab - no delayslot */
- break;
- case 0x0D00: /* bt/s lab */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0) {
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
- if ((regs->sr & 0x00000001) == 0)
- regs->pc += 4; /* next after slot */
- else
-#endif
- regs->pc += SH_PC_8BIT_OFFSET(instruction);
- }
- break;
- }
- break;
-
- case 0xA000: /* bra label */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0)
- regs->pc += SH_PC_12BIT_OFFSET(instruction);
- break;
-
- case 0xB000: /* bsr label */
- ret = handle_unaligned_delayslot(regs);
- if (ret==0) {
- regs->pr = regs->pc + 4;
- regs->pc += SH_PC_12BIT_OFFSET(instruction);
- }
- break;
- }
- return ret;
-
- /* handle non-delay-slot instruction */
- simple:
- ret = handle_unaligned_ins(instruction,regs);
- if (ret==0)
- regs->pc += instruction_size(instruction);
- return ret;
+ return addr >= PAGE_OFFSET;
}
-#endif /* CONFIG_CPU_SH2A */
-
-#ifdef CONFIG_CPU_HAS_SR_RB
-#define lookup_exception_vector(x) \
- __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
-#else
-#define lookup_exception_vector(x) \
- __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
#endif
/*
- * Handle various address error exceptions:
- * - instruction address error:
- * misaligned PC
- * PC >= 0x80000000 in user mode
- * - data address error (read and write)
- * misaligned data access
- * access to >= 0x80000000 is user mode
- * Unfortuntaly we can't distinguish between instruction address error
- * and data address errors caused by read accesses.
+ * Generic trap handler.
*/
-asmlinkage void do_address_error(struct pt_regs *regs,
- unsigned long writeaccess,
- unsigned long address)
+BUILD_TRAP_HANDLER(debug)
{
- unsigned long error_code = 0;
- mm_segment_t oldfs;
- siginfo_t info;
-#ifndef CONFIG_CPU_SH2A
- u16 instruction;
- int tmp;
-#endif
-
- /* Intentional ifdef */
-#ifdef CONFIG_CPU_HAS_SR_RB
- lookup_exception_vector(error_code);
-#endif
-
- oldfs = get_fs();
-
- if (user_mode(regs)) {
- int si_code = BUS_ADRERR;
-
- local_irq_enable();
+ TRAP_HANDLER_DECL;
- /* bad PC is not something we can fix */
- if (regs->pc & 1) {
- si_code = BUS_ADRALN;
- goto uspace_segv;
- }
+ /* Rewind */
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-#ifndef CONFIG_CPU_SH2A
- set_fs(USER_DS);
- if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
- /* Argh. Fault on the instruction itself.
- This should never happen non-SMP
- */
- set_fs(oldfs);
- goto uspace_segv;
- }
-
- tmp = handle_unaligned_access(instruction, regs);
- set_fs(oldfs);
-
- if (tmp==0)
- return; /* sorted */
-#endif
-
-uspace_segv:
- printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
- "access (PC %lx PR %lx)\n", current->comm, regs->pc,
- regs->pr);
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = si_code;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGBUS, &info, current);
- } else {
- if (regs->pc & 1)
- die("unaligned program counter", regs, error_code);
-
-#ifndef CONFIG_CPU_SH2A
- set_fs(KERNEL_DS);
- if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
- /* Argh. Fault on the instruction itself.
- This should never happen non-SMP
- */
- set_fs(oldfs);
- die("insn faulting in do_address_error", regs, 0);
- }
-
- handle_unaligned_access(instruction, regs);
- set_fs(oldfs);
-#else
- printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
- "access\n", current->comm);
+ if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
- force_sig(SIGSEGV, current);
-#endif
- }
+ force_sig(SIGTRAP, current);
}
-#ifdef CONFIG_SH_DSP
/*
- * SH-DSP support gerg@snapgear.com.
+ * Special handler for BUG() traps.
*/
-int is_dsp_inst(struct pt_regs *regs)
+BUILD_TRAP_HANDLER(bug)
{
- unsigned short inst = 0;
-
- /*
- * Safe guard if DSP mode is already enabled or we're lacking
- * the DSP altogether.
- */
- if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
- return 0;
-
- get_user(inst, ((unsigned short *) regs->pc));
-
- inst &= 0xf000;
-
- /* Check for any type of DSP or support instruction */
- if ((inst == 0xf000) || (inst == 0x4000))
- return 1;
-
- return 0;
-}
-#else
-#define is_dsp_inst(regs) (0)
-#endif /* CONFIG_SH_DSP */
+ TRAP_HANDLER_DECL;
-#ifdef CONFIG_CPU_SH2A
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- siginfo_t info;
-
- switch (r4) {
- case TRAP_DIVZERO_ERROR:
- info.si_code = FPE_INTDIV;
- break;
- case TRAP_DIVOVF_ERROR:
- info.si_code = FPE_INTOVF;
- break;
- }
-
- force_sig_info(SIGFPE, &info, current);
-}
-#endif
-
-/* arch/sh/kernel/cpu/sh4/fpu.c */
-extern int do_fpu_inst(unsigned short, struct pt_regs *);
-extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7, struct pt_regs __regs);
-
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- unsigned long error_code;
- struct task_struct *tsk = current;
-
-#ifdef CONFIG_SH_FPU_EMU
- unsigned short inst = 0;
- int err;
-
- get_user(inst, (unsigned short*)regs->pc);
-
- err = do_fpu_inst(inst, regs);
- if (!err) {
- regs->pc += instruction_size(inst);
- return;
- }
- /* not a FPU inst. */
-#endif
+ /* Rewind */
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-#ifdef CONFIG_SH_DSP
- /* Check if it's a DSP instruction */
- if (is_dsp_inst(regs)) {
- /* Enable DSP mode, and restart instruction. */
- regs->sr |= SR_DSP;
+ if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
return;
- }
-#endif
-
- lookup_exception_vector(error_code);
-
- local_irq_enable();
- CHK_REMOTE_DEBUG(regs);
- force_sig(SIGILL, tsk);
- die_if_no_fixup("reserved instruction", regs, error_code);
-}
-
-#ifdef CONFIG_SH_FPU_EMU
-static int emulate_branch(unsigned short inst, struct pt_regs* regs)
-{
- /*
- * bfs: 8fxx: PC+=d*2+4;
- * bts: 8dxx: PC+=d*2+4;
- * bra: axxx: PC+=D*2+4;
- * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
- * braf:0x23: PC+=Rn*2+4;
- * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
- * jmp: 4x2b: PC=Rn;
- * jsr: 4x0b: PC=Rn after PR=PC+4;
- * rts: 000b: PC=PR;
- */
- if ((inst & 0xfd00) == 0x8d00) {
- regs->pc += SH_PC_8BIT_OFFSET(inst);
- return 0;
- }
-
- if ((inst & 0xe000) == 0xa000) {
- regs->pc += SH_PC_12BIT_OFFSET(inst);
- return 0;
- }
-
- if ((inst & 0xf0df) == 0x0003) {
- regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
- return 0;
- }
-
- if ((inst & 0xf0df) == 0x400b) {
- regs->pc = regs->regs[(inst & 0x0f00) >> 8];
- return 0;
- }
-
- if ((inst & 0xffff) == 0x000b) {
- regs->pc = regs->pr;
- return 0;
- }
-
- return 1;
-}
-#endif
-
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- unsigned long error_code;
- struct task_struct *tsk = current;
-#ifdef CONFIG_SH_FPU_EMU
- unsigned short inst = 0;
-
- get_user(inst, (unsigned short *)regs->pc + 1);
- if (!do_fpu_inst(inst, regs)) {
- get_user(inst, (unsigned short *)regs->pc);
- if (!emulate_branch(inst, regs))
- return;
- /* fault in branch.*/
- }
- /* not a FPU inst. */
-#endif
-
- lookup_exception_vector(error_code);
-
- local_irq_enable();
- CHK_REMOTE_DEBUG(regs);
- force_sig(SIGILL, tsk);
- die_if_no_fixup("illegal slot instruction", regs, error_code);
-}
-
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- long ex;
-
- lookup_exception_vector(ex);
- die_if_kernel("exception", regs, ex);
-}
-
-#if defined(CONFIG_SH_STANDARD_BIOS)
-void *gdb_vbr_vector;
-
-static inline void __init gdb_vbr_init(void)
-{
- register unsigned long vbr;
-
- /*
- * Read the old value of the VBR register to initialise
- * the vector through which debug and BIOS traps are
- * delegated by the Linux trap handler.
- */
- asm volatile("stc vbr, %0" : "=r" (vbr));
-
- gdb_vbr_vector = (void *)(vbr + 0x100);
- printk("Setting GDB trap vector to 0x%08lx\n",
- (unsigned long)gdb_vbr_vector);
-}
-#endif
-
-void __cpuinit per_cpu_trap_init(void)
-{
- extern void *vbr_base;
-
-#ifdef CONFIG_SH_STANDARD_BIOS
- if (raw_smp_processor_id() == 0)
- gdb_vbr_init();
-#endif
-
- /* NOTE: The VBR value should be at P1
- (or P2, virtural "fixed" address space).
- It's definitely should not in physical address. */
-
- asm volatile("ldc %0, vbr"
- : /* no output */
- : "r" (&vbr_base)
- : "memory");
-}
-
-void *set_exception_table_vec(unsigned int vec, void *handler)
-{
- extern void *exception_handling_table[];
- void *old_handler;
-
- old_handler = exception_handling_table[vec];
- exception_handling_table[vec] = handler;
- return old_handler;
-}
-
-extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-
-void __init trap_init(void)
-{
- set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
- set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
-
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
- defined(CONFIG_SH_FPU_EMU)
- /*
- * For SH-4 lacking an FPU, treat floating point instructions as
- * reserved. They'll be handled in the math-emu case, or faulted on
- * otherwise.
- */
- set_exception_table_evt(0x800, do_reserved_inst);
- set_exception_table_evt(0x820, do_illegal_slot_inst);
-#elif defined(CONFIG_SH_FPU)
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
- set_exception_table_evt(0xd80, do_fpu_state_restore);
- set_exception_table_evt(0xda0, do_fpu_state_restore);
-#else
- set_exception_table_evt(0x800, do_fpu_state_restore);
- set_exception_table_evt(0x820, do_fpu_state_restore);
-#endif
-#endif
-
-#ifdef CONFIG_CPU_SH2
- set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
-#endif
-#ifdef CONFIG_CPU_SH2A
- set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
- set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
-#endif
-
- /* Setup VBR for boot cpu */
- per_cpu_trap_init();
-}
#ifdef CONFIG_BUG
-void handle_BUG(struct pt_regs *regs)
-{
- enum bug_trap_type tt;
- tt = report_bug(regs->pc, regs);
- if (tt == BUG_TRAP_TYPE_WARN) {
- regs->pc += 2;
- return;
+ if (__kernel_text_address(instruction_pointer(regs))) {
+ opcode_t insn = *(opcode_t *)instruction_pointer(regs);
+ if (insn == TRAPA_BUG_OPCODE)
+ handle_BUG(regs);
}
-
- die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
-}
-
-int is_valid_bugaddr(unsigned long addr)
-{
- return addr >= PAGE_OFFSET;
-}
-#endif
-
-void show_trace(struct task_struct *tsk, unsigned long *sp,
- struct pt_regs *regs)
-{
- unsigned long addr;
-
- if (regs && user_mode(regs))
- return;
-
- printk("\nCall trace: ");
-#ifdef CONFIG_KALLSYMS
- printk("\n");
#endif
- while (!kstack_end(sp)) {
- addr = *sp++;
- if (kernel_text_address(addr))
- print_ip_sym(addr);
- }
-
- printk("\n");
-
- if (!tsk)
- tsk = current;
-
- debug_show_held_locks(tsk);
-}
-
-void show_stack(struct task_struct *tsk, unsigned long *sp)
-{
- unsigned long stack;
-
- if (!tsk)
- tsk = current;
- if (tsk == current)
- sp = (unsigned long *)current_stack_pointer;
- else
- sp = (unsigned long *)tsk->thread.sp;
-
- stack = (unsigned long)sp;
- dump_mem("Stack: ", stack, THREAD_SIZE +
- (unsigned long)task_stack_page(tsk));
- show_trace(tsk, sp, NULL);
-}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
+ force_sig(SIGTRAP, current);
}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
new file mode 100644
index 000000000000..2e58f7a6b746
--- /dev/null
+++ b/arch/sh/kernel/traps_32.c
@@ -0,0 +1,919 @@
+/*
+ * 'traps.c' handles hardware traps and faults after we have saved some
+ * state in 'entry.S'.
+ *
+ * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2000 Philipp Rumpf
+ * Copyright (C) 2000 David Howells
+ * Copyright (C) 2002 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/io.h>
+#include <linux/bug.h>
+#include <linux/debug_locks.h>
+#include <linux/kdebug.h>
+#include <linux/kexec.h>
+#include <linux/limits.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+#define CHK_REMOTE_DEBUG(regs) \
+{ \
+ if (kgdb_debug_hook && !user_mode(regs))\
+ (*kgdb_debug_hook)(regs); \
+}
+#else
+#define CHK_REMOTE_DEBUG(regs)
+#endif
+
+#ifdef CONFIG_CPU_SH2
+# define TRAP_RESERVED_INST 4
+# define TRAP_ILLEGAL_SLOT_INST 6
+# define TRAP_ADDRESS_ERROR 9
+# ifdef CONFIG_CPU_SH2A
+# define TRAP_DIVZERO_ERROR 17
+# define TRAP_DIVOVF_ERROR 18
+# endif
+#else
+#define TRAP_RESERVED_INST 12
+#define TRAP_ILLEGAL_SLOT_INST 13
+#endif
+
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+{
+ unsigned long p;
+ int i;
+
+ printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+
+ for (p = bottom & ~31; p < top; ) {
+ printk("%04lx: ", p & 0xffff);
+
+ for (i = 0; i < 8; i++, p += 4) {
+ unsigned int val;
+
+ if (p < bottom || p >= top)
+ printk(" ");
+ else {
+ if (__get_user(val, (unsigned int __user *)p)) {
+ printk("\n");
+ return;
+ }
+ printk("%08x ", val);
+ }
+ }
+ printk("\n");
+ }
+}
+
+static DEFINE_SPINLOCK(die_lock);
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ static int die_counter;
+
+ oops_enter();
+
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ bust_spinlocks(1);
+
+ printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+
+ CHK_REMOTE_DEBUG(regs);
+ print_modules();
+ show_regs(regs);
+
+ printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
+ task_pid_nr(current), task_stack_page(current) + 1);
+
+ if (!user_mode(regs) || in_interrupt())
+ dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
+ (unsigned long)task_stack_page(current));
+
+ bust_spinlocks(0);
+ add_taint(TAINT_DIE);
+ spin_unlock_irq(&die_lock);
+
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops)
+ panic("Fatal exception");
+
+ oops_exit();
+ do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char *str, struct pt_regs *regs,
+ long err)
+{
+ if (!user_mode(regs))
+ die(str, regs, err);
+}
+
+/*
+ * try and fix up kernelspace address errors
+ * - userspace errors just cause EFAULT to be returned, resulting in SEGV
+ * - kernel/userspace interfaces cause a jump to an appropriate handler
+ * - other kernel errors are bad
+ * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
+ */
+static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+{
+ if (!user_mode(regs)) {
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return 0;
+ }
+ die(str, regs, err);
+ }
+ return -EFAULT;
+}
+
+/*
+ * handle an instruction that does an unaligned memory access by emulating the
+ * desired behaviour
+ * - note that PC _may not_ point to the faulting instruction
+ * (if that instruction is in a branch delay slot)
+ * - return 0 if emulation okay, -EFAULT on existential error
+ */
+static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
+{
+ int ret, index, count;
+ unsigned long *rm, *rn;
+ unsigned char *src, *dst;
+
+ index = (instruction>>8)&15; /* 0x0F00 */
+ rn = &regs->regs[index];
+
+ index = (instruction>>4)&15; /* 0x00F0 */
+ rm = &regs->regs[index];
+
+ count = 1<<(instruction&3);
+
+ ret = -EFAULT;
+ switch (instruction>>12) {
+ case 0: /* mov.[bwl] to/from memory via r0+rn */
+ if (instruction & 8) {
+ /* from memory */
+ src = (unsigned char*) *rm;
+ src += regs->regs[0];
+ dst = (unsigned char*) rn;
+ *(unsigned long*)dst = 0;
+
+#ifdef __LITTLE_ENDIAN__
+ if (copy_from_user(dst, src, count))
+ goto fetch_fault;
+
+ if ((count == 2) && dst[1] & 0x80) {
+ dst[2] = 0xff;
+ dst[3] = 0xff;
+ }
+#else
+ dst += 4-count;
+
+ if (__copy_user(dst, src, count))
+ goto fetch_fault;
+
+ if ((count == 2) && dst[2] & 0x80) {
+ dst[0] = 0xff;
+ dst[1] = 0xff;
+ }
+#endif
+ } else {
+ /* to memory */
+ src = (unsigned char*) rm;
+#if !defined(__LITTLE_ENDIAN__)
+ src += 4-count;
+#endif
+ dst = (unsigned char*) *rn;
+ dst += regs->regs[0];
+
+ if (copy_to_user(dst, src, count))
+ goto fetch_fault;
+ }
+ ret = 0;
+ break;
+
+ case 1: /* mov.l Rm,@(disp,Rn) */
+ src = (unsigned char*) rm;
+ dst = (unsigned char*) *rn;
+ dst += (instruction&0x000F)<<2;
+
+ if (copy_to_user(dst,src,4))
+ goto fetch_fault;
+ ret = 0;
+ break;
+
+ case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
+ if (instruction & 4)
+ *rn -= count;
+ src = (unsigned char*) rm;
+ dst = (unsigned char*) *rn;
+#if !defined(__LITTLE_ENDIAN__)
+ src += 4-count;
+#endif
+ if (copy_to_user(dst, src, count))
+ goto fetch_fault;
+ ret = 0;
+ break;
+
+ case 5: /* mov.l @(disp,Rm),Rn */
+ src = (unsigned char*) *rm;
+ src += (instruction&0x000F)<<2;
+ dst = (unsigned char*) rn;
+ *(unsigned long*)dst = 0;
+
+ if (copy_from_user(dst,src,4))
+ goto fetch_fault;
+ ret = 0;
+ break;
+
+ case 6: /* mov.[bwl] from memory, possibly with post-increment */
+ src = (unsigned char*) *rm;
+ if (instruction & 4)
+ *rm += count;
+ dst = (unsigned char*) rn;
+ *(unsigned long*)dst = 0;
+
+#ifdef __LITTLE_ENDIAN__
+ if (copy_from_user(dst, src, count))
+ goto fetch_fault;
+
+ if ((count == 2) && dst[1] & 0x80) {
+ dst[2] = 0xff;
+ dst[3] = 0xff;
+ }
+#else
+ dst += 4-count;
+
+ if (copy_from_user(dst, src, count))
+ goto fetch_fault;
+
+ if ((count == 2) && dst[2] & 0x80) {
+ dst[0] = 0xff;
+ dst[1] = 0xff;
+ }
+#endif
+ ret = 0;
+ break;
+
+ case 8:
+ switch ((instruction&0xFF00)>>8) {
+ case 0x81: /* mov.w R0,@(disp,Rn) */
+ src = (unsigned char*) &regs->regs[0];
+#if !defined(__LITTLE_ENDIAN__)
+ src += 2;
+#endif
+ dst = (unsigned char*) *rm; /* called Rn in the spec */
+ dst += (instruction&0x000F)<<1;
+
+ if (copy_to_user(dst, src, 2))
+ goto fetch_fault;
+ ret = 0;
+ break;
+
+ case 0x85: /* mov.w @(disp,Rm),R0 */
+ src = (unsigned char*) *rm;
+ src += (instruction&0x000F)<<1;
+ dst = (unsigned char*) &regs->regs[0];
+ *(unsigned long*)dst = 0;
+
+#if !defined(__LITTLE_ENDIAN__)
+ dst += 2;
+#endif
+
+ if (copy_from_user(dst, src, 2))
+ goto fetch_fault;
+
+#ifdef __LITTLE_ENDIAN__
+ if (dst[1] & 0x80) {
+ dst[2] = 0xff;
+ dst[3] = 0xff;
+ }
+#else
+ if (dst[2] & 0x80) {
+ dst[0] = 0xff;
+ dst[1] = 0xff;
+ }
+#endif
+ ret = 0;
+ break;
+ }
+ break;
+ }
+ return ret;
+
+ fetch_fault:
+ /* Argh. Address not only misaligned but also non-existent.
+ * Raise an EFAULT and see if it's trapped
+ */
+ return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
+}
+
+/*
+ * emulate the instruction in the delay slot
+ * - fetches the instruction from PC+2
+ */
+static inline int handle_unaligned_delayslot(struct pt_regs *regs)
+{
+ u16 instruction;
+
+ if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
+ /* the instruction-fetch faulted */
+ if (user_mode(regs))
+ return -EFAULT;
+
+ /* kernel */
+ die("delay-slot-insn faulting in handle_unaligned_delayslot",
+ regs, 0);
+ }
+
+ return handle_unaligned_ins(instruction,regs);
+}
+
+/*
+ * handle an instruction that does an unaligned memory access
+ * - have to be careful of branch delay-slot instructions that fault
+ * SH3:
+ * - if the branch would be taken PC points to the branch
+ * - if the branch would not be taken, PC points to delay-slot
+ * SH4:
+ * - PC always points to delayed branch
+ * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
+ */
+
+/* Macros to determine offset from current PC for branch instructions */
+/* Explicit type coercion is used to force sign extension where needed */
+#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
+#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
+
+/*
+ * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
+ * opcodes..
+ */
+#ifndef CONFIG_CPU_SH2A
+static int handle_unaligned_notify_count = 10;
+
+static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
+{
+ u_int rm;
+ int ret, index;
+
+ index = (instruction>>8)&15; /* 0x0F00 */
+ rm = regs->regs[index];
+
+ /* shout about the first ten userspace fixups */
+ if (user_mode(regs) && handle_unaligned_notify_count>0) {
+ handle_unaligned_notify_count--;
+
+ printk(KERN_NOTICE "Fixing up unaligned userspace access "
+ "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+ current->comm, task_pid_nr(current),
+ (u16 *)regs->pc, instruction);
+ }
+
+ ret = -EFAULT;
+ switch (instruction&0xF000) {
+ case 0x0000:
+ if (instruction==0x000B) {
+ /* rts */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0)
+ regs->pc = regs->pr;
+ }
+ else if ((instruction&0x00FF)==0x0023) {
+ /* braf @Rm */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0)
+ regs->pc += rm + 4;
+ }
+ else if ((instruction&0x00FF)==0x0003) {
+ /* bsrf @Rm */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0) {
+ regs->pr = regs->pc + 4;
+ regs->pc += rm + 4;
+ }
+ }
+ else {
+ /* mov.[bwl] to/from memory via r0+rn */
+ goto simple;
+ }
+ break;
+
+ case 0x1000: /* mov.l Rm,@(disp,Rn) */
+ goto simple;
+
+ case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
+ goto simple;
+
+ case 0x4000:
+ if ((instruction&0x00FF)==0x002B) {
+ /* jmp @Rm */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0)
+ regs->pc = rm;
+ }
+ else if ((instruction&0x00FF)==0x000B) {
+ /* jsr @Rm */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0) {
+ regs->pr = regs->pc + 4;
+ regs->pc = rm;
+ }
+ }
+ else {
+ /* mov.[bwl] to/from memory via r0+rn */
+ goto simple;
+ }
+ break;
+
+ case 0x5000: /* mov.l @(disp,Rm),Rn */
+ goto simple;
+
+ case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
+ goto simple;
+
+ case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
+ switch (instruction&0x0F00) {
+ case 0x0100: /* mov.w R0,@(disp,Rm) */
+ goto simple;
+ case 0x0500: /* mov.w @(disp,Rm),R0 */
+ goto simple;
+ case 0x0B00: /* bf lab - no delayslot*/
+ break;
+ case 0x0F00: /* bf/s lab */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0) {
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+ if ((regs->sr & 0x00000001) != 0)
+ regs->pc += 4; /* next after slot */
+ else
+#endif
+ regs->pc += SH_PC_8BIT_OFFSET(instruction);
+ }
+ break;
+ case 0x0900: /* bt lab - no delayslot */
+ break;
+ case 0x0D00: /* bt/s lab */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0) {
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+ if ((regs->sr & 0x00000001) == 0)
+ regs->pc += 4; /* next after slot */
+ else
+#endif
+ regs->pc += SH_PC_8BIT_OFFSET(instruction);
+ }
+ break;
+ }
+ break;
+
+ case 0xA000: /* bra label */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0)
+ regs->pc += SH_PC_12BIT_OFFSET(instruction);
+ break;
+
+ case 0xB000: /* bsr label */
+ ret = handle_unaligned_delayslot(regs);
+ if (ret==0) {
+ regs->pr = regs->pc + 4;
+ regs->pc += SH_PC_12BIT_OFFSET(instruction);
+ }
+ break;
+ }
+ return ret;
+
+ /* handle non-delay-slot instruction */
+ simple:
+ ret = handle_unaligned_ins(instruction,regs);
+ if (ret==0)
+ regs->pc += instruction_size(instruction);
+ return ret;
+}
+#endif /* CONFIG_CPU_SH2A */
+
+#ifdef CONFIG_CPU_HAS_SR_RB
+#define lookup_exception_vector(x) \
+ __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
+#else
+#define lookup_exception_vector(x) \
+ __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
+#endif
+
+/*
+ * Handle various address error exceptions:
+ * - instruction address error:
+ * misaligned PC
+ * PC >= 0x80000000 in user mode
+ * - data address error (read and write)
+ * misaligned data access
+ * access to >= 0x80000000 is user mode
+ * Unfortuntaly we can't distinguish between instruction address error
+ * and data address errors caused by read accesses.
+ */
+asmlinkage void do_address_error(struct pt_regs *regs,
+ unsigned long writeaccess,
+ unsigned long address)
+{
+ unsigned long error_code = 0;
+ mm_segment_t oldfs;
+ siginfo_t info;
+#ifndef CONFIG_CPU_SH2A
+ u16 instruction;
+ int tmp;
+#endif
+
+ /* Intentional ifdef */
+#ifdef CONFIG_CPU_HAS_SR_RB
+ lookup_exception_vector(error_code);
+#endif
+
+ oldfs = get_fs();
+
+ if (user_mode(regs)) {
+ int si_code = BUS_ADRERR;
+
+ local_irq_enable();
+
+ /* bad PC is not something we can fix */
+ if (regs->pc & 1) {
+ si_code = BUS_ADRALN;
+ goto uspace_segv;
+ }
+
+#ifndef CONFIG_CPU_SH2A
+ set_fs(USER_DS);
+ if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+ /* Argh. Fault on the instruction itself.
+ This should never happen non-SMP
+ */
+ set_fs(oldfs);
+ goto uspace_segv;
+ }
+
+ tmp = handle_unaligned_access(instruction, regs);
+ set_fs(oldfs);
+
+ if (tmp==0)
+ return; /* sorted */
+#endif
+
+uspace_segv:
+ printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
+ "access (PC %lx PR %lx)\n", current->comm, regs->pc,
+ regs->pr);
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void __user *)address;
+ force_sig_info(SIGBUS, &info, current);
+ } else {
+ if (regs->pc & 1)
+ die("unaligned program counter", regs, error_code);
+
+#ifndef CONFIG_CPU_SH2A
+ set_fs(KERNEL_DS);
+ if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+ /* Argh. Fault on the instruction itself.
+ This should never happen non-SMP
+ */
+ set_fs(oldfs);
+ die("insn faulting in do_address_error", regs, 0);
+ }
+
+ handle_unaligned_access(instruction, regs);
+ set_fs(oldfs);
+#else
+ printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
+ "access\n", current->comm);
+
+ force_sig(SIGSEGV, current);
+#endif
+ }
+}
+
+#ifdef CONFIG_SH_DSP
+/*
+ * SH-DSP support gerg@snapgear.com.
+ */
+int is_dsp_inst(struct pt_regs *regs)
+{
+ unsigned short inst = 0;
+
+ /*
+ * Safe guard if DSP mode is already enabled or we're lacking
+ * the DSP altogether.
+ */
+ if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
+ return 0;
+
+ get_user(inst, ((unsigned short *) regs->pc));
+
+ inst &= 0xf000;
+
+ /* Check for any type of DSP or support instruction */
+ if ((inst == 0xf000) || (inst == 0x4000))
+ return 1;
+
+ return 0;
+}
+#else
+#define is_dsp_inst(regs) (0)
+#endif /* CONFIG_SH_DSP */
+
+#ifdef CONFIG_CPU_SH2A
+asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ siginfo_t info;
+
+ switch (r4) {
+ case TRAP_DIVZERO_ERROR:
+ info.si_code = FPE_INTDIV;
+ break;
+ case TRAP_DIVOVF_ERROR:
+ info.si_code = FPE_INTOVF;
+ break;
+ }
+
+ force_sig_info(SIGFPE, &info, current);
+}
+#endif
+
+asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ unsigned long error_code;
+ struct task_struct *tsk = current;
+
+#ifdef CONFIG_SH_FPU_EMU
+ unsigned short inst = 0;
+ int err;
+
+ get_user(inst, (unsigned short*)regs->pc);
+
+ err = do_fpu_inst(inst, regs);
+ if (!err) {
+ regs->pc += instruction_size(inst);
+ return;
+ }
+ /* not a FPU inst. */
+#endif
+
+#ifdef CONFIG_SH_DSP
+ /* Check if it's a DSP instruction */
+ if (is_dsp_inst(regs)) {
+ /* Enable DSP mode, and restart instruction. */
+ regs->sr |= SR_DSP;
+ return;
+ }
+#endif
+
+ lookup_exception_vector(error_code);
+
+ local_irq_enable();
+ CHK_REMOTE_DEBUG(regs);
+ force_sig(SIGILL, tsk);
+ die_if_no_fixup("reserved instruction", regs, error_code);
+}
+
+#ifdef CONFIG_SH_FPU_EMU
+static int emulate_branch(unsigned short inst, struct pt_regs* regs)
+{
+ /*
+ * bfs: 8fxx: PC+=d*2+4;
+ * bts: 8dxx: PC+=d*2+4;
+ * bra: axxx: PC+=D*2+4;
+ * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
+ * braf:0x23: PC+=Rn*2+4;
+ * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
+ * jmp: 4x2b: PC=Rn;
+ * jsr: 4x0b: PC=Rn after PR=PC+4;
+ * rts: 000b: PC=PR;
+ */
+ if ((inst & 0xfd00) == 0x8d00) {
+ regs->pc += SH_PC_8BIT_OFFSET(inst);
+ return 0;
+ }
+
+ if ((inst & 0xe000) == 0xa000) {
+ regs->pc += SH_PC_12BIT_OFFSET(inst);
+ return 0;
+ }
+
+ if ((inst & 0xf0df) == 0x0003) {
+ regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
+ return 0;
+ }
+
+ if ((inst & 0xf0df) == 0x400b) {
+ regs->pc = regs->regs[(inst & 0x0f00) >> 8];
+ return 0;
+ }
+
+ if ((inst & 0xffff) == 0x000b) {
+ regs->pc = regs->pr;
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ unsigned long error_code;
+ struct task_struct *tsk = current;
+#ifdef CONFIG_SH_FPU_EMU
+ unsigned short inst = 0;
+
+ get_user(inst, (unsigned short *)regs->pc + 1);
+ if (!do_fpu_inst(inst, regs)) {
+ get_user(inst, (unsigned short *)regs->pc);
+ if (!emulate_branch(inst, regs))
+ return;
+ /* fault in branch.*/
+ }
+ /* not a FPU inst. */
+#endif
+
+ lookup_exception_vector(error_code);
+
+ local_irq_enable();
+ CHK_REMOTE_DEBUG(regs);
+ force_sig(SIGILL, tsk);
+ die_if_no_fixup("illegal slot instruction", regs, error_code);
+}
+
+asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ long ex;
+
+ lookup_exception_vector(ex);
+ die_if_kernel("exception", regs, ex);
+}
+
+#if defined(CONFIG_SH_STANDARD_BIOS)
+void *gdb_vbr_vector;
+
+static inline void __init gdb_vbr_init(void)
+{
+ register unsigned long vbr;
+
+ /*
+ * Read the old value of the VBR register to initialise
+ * the vector through which debug and BIOS traps are
+ * delegated by the Linux trap handler.
+ */
+ asm volatile("stc vbr, %0" : "=r" (vbr));
+
+ gdb_vbr_vector = (void *)(vbr + 0x100);
+ printk("Setting GDB trap vector to 0x%08lx\n",
+ (unsigned long)gdb_vbr_vector);
+}
+#endif
+
+void __cpuinit per_cpu_trap_init(void)
+{
+ extern void *vbr_base;
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+ if (raw_smp_processor_id() == 0)
+ gdb_vbr_init();
+#endif
+
+ /* NOTE: The VBR value should be at P1
+ (or P2, virtural "fixed" address space).
+ It's definitely should not in physical address. */
+
+ asm volatile("ldc %0, vbr"
+ : /* no output */
+ : "r" (&vbr_base)
+ : "memory");
+}
+
+void *set_exception_table_vec(unsigned int vec, void *handler)
+{
+ extern void *exception_handling_table[];
+ void *old_handler;
+
+ old_handler = exception_handling_table[vec];
+ exception_handling_table[vec] = handler;
+ return old_handler;
+}
+
+void __init trap_init(void)
+{
+ set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
+ set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
+
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
+ defined(CONFIG_SH_FPU_EMU)
+ /*
+ * For SH-4 lacking an FPU, treat floating point instructions as
+ * reserved. They'll be handled in the math-emu case, or faulted on
+ * otherwise.
+ */
+ set_exception_table_evt(0x800, do_reserved_inst);
+ set_exception_table_evt(0x820, do_illegal_slot_inst);
+#elif defined(CONFIG_SH_FPU)
+#ifdef CONFIG_CPU_SUBTYPE_SHX3
+ set_exception_table_evt(0xd80, fpu_state_restore_trap_handler);
+ set_exception_table_evt(0xda0, fpu_state_restore_trap_handler);
+#else
+ set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
+ set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
+#endif
+#endif
+
+#ifdef CONFIG_CPU_SH2
+ set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
+#endif
+#ifdef CONFIG_CPU_SH2A
+ set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
+ set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
+#endif
+
+ /* Setup VBR for boot cpu */
+ per_cpu_trap_init();
+}
+
+void show_trace(struct task_struct *tsk, unsigned long *sp,
+ struct pt_regs *regs)
+{
+ unsigned long addr;
+
+ if (regs && user_mode(regs))
+ return;
+
+ printk("\nCall trace: ");
+#ifdef CONFIG_KALLSYMS
+ printk("\n");
+#endif
+
+ while (!kstack_end(sp)) {
+ addr = *sp++;
+ if (kernel_text_address(addr))
+ print_ip_sym(addr);
+ }
+
+ printk("\n");
+
+ if (!tsk)
+ tsk = current;
+
+ debug_show_held_locks(tsk);
+}
+
+void show_stack(struct task_struct *tsk, unsigned long *sp)
+{
+ unsigned long stack;
+
+ if (!tsk)
+ tsk = current;
+ if (tsk == current)
+ sp = (unsigned long *)current_stack_pointer;
+ else
+ sp = (unsigned long *)tsk->thread.sp;
+
+ stack = (unsigned long)sp;
+ dump_mem("Stack: ", stack, THREAD_SIZE +
+ (unsigned long)task_stack_page(tsk));
+ show_trace(tsk, sp, NULL);
+}
+
+void dump_stack(void)
+{
+ show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
new file mode 100644
index 000000000000..c0b3c6f6edb5
--- /dev/null
+++ b/arch/sh/kernel/traps_64.c
@@ -0,0 +1,975 @@
+/*
+ * arch/sh/kernel/traps_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003, 2004 Paul Mundt
+ * Copyright (C) 2003, 2004 Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+
+#undef DEBUG_EXCEPTION
+#ifdef DEBUG_EXCEPTION
+/* implemented in ../lib/dbg.c */
+extern void show_excp_regs(char *fname, int trapnr, int signr,
+ struct pt_regs *regs);
+#else
+#define show_excp_regs(a, b, c, d)
+#endif
+
+static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
+ unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk);
+
+#define DO_ERROR(trapnr, signr, str, name, tsk) \
+asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
+{ \
+ do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
+}
+
+spinlock_t die_lock;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ printk("%s: %lx\n", str, (err & 0xffffff));
+ show_regs(regs);
+ spin_unlock_irq(&die_lock);
+ do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+ if (!user_mode(regs))
+ die(str, regs, err);
+}
+
+static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+{
+ if (!user_mode(regs)) {
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return;
+ }
+ die(str, regs, err);
+ }
+}
+
+DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
+DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current)
+
+
+/* Implement misaligned load/store handling for kernel (and optionally for user
+ mode too). Limitation : only SHmedia mode code is handled - there is no
+ handling at all for misaligned accesses occurring in SHcompact code yet. */
+
+static int misaligned_fixup(struct pt_regs *regs);
+
+asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs)
+{
+ if (misaligned_fixup(regs) < 0) {
+ do_unhandled_exception(7, SIGSEGV, "address error(load)",
+ "do_address_error_load",
+ error_code, regs, current);
+ }
+ return;
+}
+
+asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs)
+{
+ if (misaligned_fixup(regs) < 0) {
+ do_unhandled_exception(8, SIGSEGV, "address error(store)",
+ "do_address_error_store",
+ error_code, regs, current);
+ }
+ return;
+}
+
+#if defined(CONFIG_SH64_ID2815_WORKAROUND)
+
+#define OPCODE_INVALID 0
+#define OPCODE_USER_VALID 1
+#define OPCODE_PRIV_VALID 2
+
+/* getcon/putcon - requires checking which control register is referenced. */
+#define OPCODE_CTRL_REG 3
+
+/* Table of valid opcodes for SHmedia mode.
+ Form a 10-bit value by concatenating the major/minor opcodes i.e.
+ opcode[31:26,20:16]. The 6 MSBs of this value index into the following
+ array. The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to
+ LSBs==4'b0000 etc). */
+static unsigned long shmedia_opcode_table[64] = {
+ 0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015,
+ 0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000,
+ 0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+ 0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+ 0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+ 0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000
+};
+
+void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)
+{
+ /* Workaround SH5-101 cut2 silicon defect #2815 :
+ in some situations, inter-mode branches from SHcompact -> SHmedia
+ which should take ITLBMISS or EXECPROT exceptions at the target
+ falsely take RESINST at the target instead. */
+
+ unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */
+ unsigned long pc, aligned_pc;
+ int get_user_error;
+ int trapnr = 12;
+ int signr = SIGILL;
+ char *exception_name = "reserved_instruction";
+
+ pc = regs->pc;
+ if ((pc & 3) == 1) {
+ /* SHmedia : check for defect. This requires executable vmas
+ to be readable too. */
+ aligned_pc = pc & ~3;
+ if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
+ get_user_error = -EFAULT;
+ } else {
+ get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
+ }
+ if (get_user_error >= 0) {
+ unsigned long index, shift;
+ unsigned long major, minor, combined;
+ unsigned long reserved_field;
+ reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */
+ major = (opcode >> 26) & 0x3f;
+ minor = (opcode >> 16) & 0xf;
+ combined = (major << 4) | minor;
+ index = major;
+ shift = minor << 1;
+ if (reserved_field == 0) {
+ int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3;
+ switch (opcode_state) {
+ case OPCODE_INVALID:
+ /* Trap. */
+ break;
+ case OPCODE_USER_VALID:
+ /* Restart the instruction : the branch to the instruction will now be from an RTE
+ not from SHcompact so the silicon defect won't be triggered. */
+ return;
+ case OPCODE_PRIV_VALID:
+ if (!user_mode(regs)) {
+ /* Should only ever get here if a module has
+ SHcompact code inside it. If so, the same fix up is needed. */
+ return; /* same reason */
+ }
+ /* Otherwise, user mode trying to execute a privileged instruction -
+ fall through to trap. */
+ break;
+ case OPCODE_CTRL_REG:
+ /* If in privileged mode, return as above. */
+ if (!user_mode(regs)) return;
+ /* In user mode ... */
+ if (combined == 0x9f) { /* GETCON */
+ unsigned long regno = (opcode >> 20) & 0x3f;
+ if (regno >= 62) {
+ return;
+ }
+ /* Otherwise, reserved or privileged control register, => trap */
+ } else if (combined == 0x1bf) { /* PUTCON */
+ unsigned long regno = (opcode >> 4) & 0x3f;
+ if (regno >= 62) {
+ return;
+ }
+ /* Otherwise, reserved or privileged control register, => trap */
+ } else {
+ /* Trap */
+ }
+ break;
+ default:
+ /* Fall through to trap. */
+ break;
+ }
+ }
+ /* fall through to normal resinst processing */
+ } else {
+ /* Error trying to read opcode. This typically means a
+ real fault, not a RESINST any more. So change the
+ codes. */
+ trapnr = 87;
+ exception_name = "address error (exec)";
+ signr = SIGSEGV;
+ }
+ }
+
+ do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current);
+}
+
+#else /* CONFIG_SH64_ID2815_WORKAROUND */
+
+/* If the workaround isn't needed, this is just a straightforward reserved
+ instruction */
+DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current)
+
+#endif /* CONFIG_SH64_ID2815_WORKAROUND */
+
+/* Called with interrupts disabled */
+asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs)
+{
+ show_excp_regs(__FUNCTION__, -1, -1, regs);
+ die_if_kernel("exception", regs, ex);
+}
+
+int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
+{
+ /* Syscall debug */
+ printk("System call ID error: [0x1#args:8 #syscall:16 0x%lx]\n", scId);
+
+ die_if_kernel("unknown trapa", regs, scId);
+
+ return -ENOSYS;
+}
+
+void show_stack(struct task_struct *tsk, unsigned long *sp)
+{
+#ifdef CONFIG_KALLSYMS
+ extern void sh64_unwind(struct pt_regs *regs);
+ struct pt_regs *regs;
+
+ regs = tsk ? tsk->thread.kregs : NULL;
+
+ sh64_unwind(regs);
+#else
+ printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
+#endif
+}
+
+void show_task(unsigned long *sp)
+{
+ show_stack(NULL, sp);
+}
+
+void dump_stack(void)
+{
+ show_task(NULL);
+}
+/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
+EXPORT_SYMBOL(dump_stack);
+
+static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
+ unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
+{
+ show_excp_regs(fn_name, trapnr, signr, regs);
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
+
+ if (user_mode(regs))
+ force_sig(signr, tsk);
+
+ die_if_no_fixup(str, regs, error_code);
+}
+
+static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode)
+{
+ int get_user_error;
+ unsigned long aligned_pc;
+ unsigned long opcode;
+
+ if ((pc & 3) == 1) {
+ /* SHmedia */
+ aligned_pc = pc & ~3;
+ if (from_user_mode) {
+ if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
+ get_user_error = -EFAULT;
+ } else {
+ get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
+ *result_opcode = opcode;
+ }
+ return get_user_error;
+ } else {
+ /* If the fault was in the kernel, we can either read
+ * this directly, or if not, we fault.
+ */
+ *result_opcode = *(unsigned long *) aligned_pc;
+ return 0;
+ }
+ } else if ((pc & 1) == 0) {
+ /* SHcompact */
+ /* TODO : provide handling for this. We don't really support
+ user-mode SHcompact yet, and for a kernel fault, this would
+ have to come from a module built for SHcompact. */
+ return -EFAULT;
+ } else {
+ /* misaligned */
+ return -EFAULT;
+ }
+}
+
+static int address_is_sign_extended(__u64 a)
+{
+ __u64 b;
+#if (NEFF == 32)
+ b = (__u64)(__s64)(__s32)(a & 0xffffffffUL);
+ return (b == a) ? 1 : 0;
+#else
+#error "Sign extend check only works for NEFF==32"
+#endif
+}
+
+static int generate_and_check_address(struct pt_regs *regs,
+ __u32 opcode,
+ int displacement_not_indexed,
+ int width_shift,
+ __u64 *address)
+{
+ /* return -1 for fault, 0 for OK */
+
+ __u64 base_address, addr;
+ int basereg;
+
+ basereg = (opcode >> 20) & 0x3f;
+ base_address = regs->regs[basereg];
+ if (displacement_not_indexed) {
+ __s64 displacement;
+ displacement = (opcode >> 10) & 0x3ff;
+ displacement = ((displacement << 54) >> 54); /* sign extend */
+ addr = (__u64)((__s64)base_address + (displacement << width_shift));
+ } else {
+ __u64 offset;
+ int offsetreg;
+ offsetreg = (opcode >> 10) & 0x3f;
+ offset = regs->regs[offsetreg];
+ addr = base_address + offset;
+ }
+
+ /* Check sign extended */
+ if (!address_is_sign_extended(addr)) {
+ return -1;
+ }
+
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ /* Check accessible. For misaligned access in the kernel, assume the
+ address is always accessible (and if not, just fault when the
+ load/store gets done.) */
+ if (user_mode(regs)) {
+ if (addr >= TASK_SIZE) {
+ return -1;
+ }
+ /* Do access_ok check later - it depends on whether it's a load or a store. */
+ }
+#endif
+
+ *address = addr;
+ return 0;
+}
+
+/* Default value as for sh */
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+static int user_mode_unaligned_fixup_count = 10;
+static int user_mode_unaligned_fixup_enable = 1;
+#endif
+
+static int kernel_mode_unaligned_fixup_count = 32;
+
+static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)
+{
+ unsigned short x;
+ unsigned char *p, *q;
+ p = (unsigned char *) (int) address;
+ q = (unsigned char *) &x;
+ q[0] = p[0];
+ q[1] = p[1];
+
+ if (do_sign_extend) {
+ *result = (__u64)(__s64) *(short *) &x;
+ } else {
+ *result = (__u64) x;
+ }
+}
+
+static void misaligned_kernel_word_store(__u64 address, __u64 value)
+{
+ unsigned short x;
+ unsigned char *p, *q;
+ p = (unsigned char *) (int) address;
+ q = (unsigned char *) &x;
+
+ x = (__u16) value;
+ p[0] = q[0];
+ p[1] = q[1];
+}
+
+static int misaligned_load(struct pt_regs *regs,
+ __u32 opcode,
+ int displacement_not_indexed,
+ int width_shift,
+ int do_sign_extend)
+{
+ /* Return -1 for a fault, 0 for OK */
+ int error;
+ int destreg;
+ __u64 address;
+
+ error = generate_and_check_address(regs, opcode,
+ displacement_not_indexed, width_shift, &address);
+ if (error < 0) {
+ return error;
+ }
+
+ destreg = (opcode >> 4) & 0x3f;
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ if (user_mode(regs)) {
+ __u64 buffer;
+
+ if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
+ return -1;
+ }
+
+ if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
+ return -1; /* fault */
+ }
+ switch (width_shift) {
+ case 1:
+ if (do_sign_extend) {
+ regs->regs[destreg] = (__u64)(__s64) *(__s16 *) &buffer;
+ } else {
+ regs->regs[destreg] = (__u64) *(__u16 *) &buffer;
+ }
+ break;
+ case 2:
+ regs->regs[destreg] = (__u64)(__s64) *(__s32 *) &buffer;
+ break;
+ case 3:
+ regs->regs[destreg] = buffer;
+ break;
+ default:
+ printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+ } else
+#endif
+ {
+ /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
+ __u64 lo, hi;
+
+ switch (width_shift) {
+ case 1:
+ misaligned_kernel_word_load(address, do_sign_extend, &regs->regs[destreg]);
+ break;
+ case 2:
+ asm ("ldlo.l %1, 0, %0" : "=r" (lo) : "r" (address));
+ asm ("ldhi.l %1, 3, %0" : "=r" (hi) : "r" (address));
+ regs->regs[destreg] = lo | hi;
+ break;
+ case 3:
+ asm ("ldlo.q %1, 0, %0" : "=r" (lo) : "r" (address));
+ asm ("ldhi.q %1, 7, %0" : "=r" (hi) : "r" (address));
+ regs->regs[destreg] = lo | hi;
+ break;
+
+ default:
+ printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+static int misaligned_store(struct pt_regs *regs,
+ __u32 opcode,
+ int displacement_not_indexed,
+ int width_shift)
+{
+ /* Return -1 for a fault, 0 for OK */
+ int error;
+ int srcreg;
+ __u64 address;
+
+ error = generate_and_check_address(regs, opcode,
+ displacement_not_indexed, width_shift, &address);
+ if (error < 0) {
+ return error;
+ }
+
+ srcreg = (opcode >> 4) & 0x3f;
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ if (user_mode(regs)) {
+ __u64 buffer;
+
+ if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
+ return -1;
+ }
+
+ switch (width_shift) {
+ case 1:
+ *(__u16 *) &buffer = (__u16) regs->regs[srcreg];
+ break;
+ case 2:
+ *(__u32 *) &buffer = (__u32) regs->regs[srcreg];
+ break;
+ case 3:
+ buffer = regs->regs[srcreg];
+ break;
+ default:
+ printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+
+ if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
+ return -1; /* fault */
+ }
+ } else
+#endif
+ {
+ /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
+ __u64 val = regs->regs[srcreg];
+
+ switch (width_shift) {
+ case 1:
+ misaligned_kernel_word_store(address, val);
+ break;
+ case 2:
+ asm ("stlo.l %1, 0, %0" : : "r" (val), "r" (address));
+ asm ("sthi.l %1, 3, %0" : : "r" (val), "r" (address));
+ break;
+ case 3:
+ asm ("stlo.q %1, 0, %0" : : "r" (val), "r" (address));
+ asm ("sthi.q %1, 7, %0" : : "r" (val), "r" (address));
+ break;
+
+ default:
+ printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+/* Never need to fix up misaligned FPU accesses within the kernel since that's a real
+ error. */
+static int misaligned_fpu_load(struct pt_regs *regs,
+ __u32 opcode,
+ int displacement_not_indexed,
+ int width_shift,
+ int do_paired_load)
+{
+ /* Return -1 for a fault, 0 for OK */
+ int error;
+ int destreg;
+ __u64 address;
+
+ error = generate_and_check_address(regs, opcode,
+ displacement_not_indexed, width_shift, &address);
+ if (error < 0) {
+ return error;
+ }
+
+ destreg = (opcode >> 4) & 0x3f;
+ if (user_mode(regs)) {
+ __u64 buffer;
+ __u32 buflo, bufhi;
+
+ if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
+ return -1;
+ }
+
+ if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
+ return -1; /* fault */
+ }
+ /* 'current' may be the current owner of the FPU state, so
+ context switch the registers into memory so they can be
+ indexed by register number. */
+ if (last_task_used_math == current) {
+ enable_fpu();
+ save_fpu(current, regs);
+ disable_fpu();
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+
+ buflo = *(__u32*) &buffer;
+ bufhi = *(1 + (__u32*) &buffer);
+
+ switch (width_shift) {
+ case 2:
+ current->thread.fpu.hard.fp_regs[destreg] = buflo;
+ break;
+ case 3:
+ if (do_paired_load) {
+ current->thread.fpu.hard.fp_regs[destreg] = buflo;
+ current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
+ } else {
+#if defined(CONFIG_LITTLE_ENDIAN)
+ current->thread.fpu.hard.fp_regs[destreg] = bufhi;
+ current->thread.fpu.hard.fp_regs[destreg+1] = buflo;
+#else
+ current->thread.fpu.hard.fp_regs[destreg] = buflo;
+ current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
+#endif
+ }
+ break;
+ default:
+ printk("Unexpected width_shift %d in misaligned_fpu_load, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+ return 0;
+ } else {
+ die ("Misaligned FPU load inside kernel", regs, 0);
+ return -1;
+ }
+
+
+}
+
+static int misaligned_fpu_store(struct pt_regs *regs,
+ __u32 opcode,
+ int displacement_not_indexed,
+ int width_shift,
+ int do_paired_load)
+{
+ /* Return -1 for a fault, 0 for OK */
+ int error;
+ int srcreg;
+ __u64 address;
+
+ error = generate_and_check_address(regs, opcode,
+ displacement_not_indexed, width_shift, &address);
+ if (error < 0) {
+ return error;
+ }
+
+ srcreg = (opcode >> 4) & 0x3f;
+ if (user_mode(regs)) {
+ __u64 buffer;
+ /* Initialise these to NaNs. */
+ __u32 buflo=0xffffffffUL, bufhi=0xffffffffUL;
+
+ if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
+ return -1;
+ }
+
+ /* 'current' may be the current owner of the FPU state, so
+ context switch the registers into memory so they can be
+ indexed by register number. */
+ if (last_task_used_math == current) {
+ enable_fpu();
+ save_fpu(current, regs);
+ disable_fpu();
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+
+ switch (width_shift) {
+ case 2:
+ buflo = current->thread.fpu.hard.fp_regs[srcreg];
+ break;
+ case 3:
+ if (do_paired_load) {
+ buflo = current->thread.fpu.hard.fp_regs[srcreg];
+ bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
+ } else {
+#if defined(CONFIG_LITTLE_ENDIAN)
+ bufhi = current->thread.fpu.hard.fp_regs[srcreg];
+ buflo = current->thread.fpu.hard.fp_regs[srcreg+1];
+#else
+ buflo = current->thread.fpu.hard.fp_regs[srcreg];
+ bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
+#endif
+ }
+ break;
+ default:
+ printk("Unexpected width_shift %d in misaligned_fpu_store, PC=%08lx\n",
+ width_shift, (unsigned long) regs->pc);
+ break;
+ }
+
+ *(__u32*) &buffer = buflo;
+ *(1 + (__u32*) &buffer) = bufhi;
+ if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
+ return -1; /* fault */
+ }
+ return 0;
+ } else {
+ die ("Misaligned FPU load inside kernel", regs, 0);
+ return -1;
+ }
+}
+#endif
+
+static int misaligned_fixup(struct pt_regs *regs)
+{
+ unsigned long opcode;
+ int error;
+ int major, minor;
+
+#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ /* Never fixup user mode misaligned accesses without this option enabled. */
+ return -1;
+#else
+ if (!user_mode_unaligned_fixup_enable) return -1;
+#endif
+
+ error = read_opcode(regs->pc, &opcode, user_mode(regs));
+ if (error < 0) {
+ return error;
+ }
+ major = (opcode >> 26) & 0x3f;
+ minor = (opcode >> 16) & 0xf;
+
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) {
+ --user_mode_unaligned_fixup_count;
+ /* Only do 'count' worth of these reports, to remove a potential DoS against syslog */
+ printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
+ current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
+ } else
+#endif
+ if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
+ --kernel_mode_unaligned_fixup_count;
+ if (in_interrupt()) {
+ printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n",
+ (__u32)regs->pc, opcode);
+ } else {
+ printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
+ current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
+ }
+ }
+
+
+ switch (major) {
+ case (0x84>>2): /* LD.W */
+ error = misaligned_load(regs, opcode, 1, 1, 1);
+ break;
+ case (0xb0>>2): /* LD.UW */
+ error = misaligned_load(regs, opcode, 1, 1, 0);
+ break;
+ case (0x88>>2): /* LD.L */
+ error = misaligned_load(regs, opcode, 1, 2, 1);
+ break;
+ case (0x8c>>2): /* LD.Q */
+ error = misaligned_load(regs, opcode, 1, 3, 0);
+ break;
+
+ case (0xa4>>2): /* ST.W */
+ error = misaligned_store(regs, opcode, 1, 1);
+ break;
+ case (0xa8>>2): /* ST.L */
+ error = misaligned_store(regs, opcode, 1, 2);
+ break;
+ case (0xac>>2): /* ST.Q */
+ error = misaligned_store(regs, opcode, 1, 3);
+ break;
+
+ case (0x40>>2): /* indexed loads */
+ switch (minor) {
+ case 0x1: /* LDX.W */
+ error = misaligned_load(regs, opcode, 0, 1, 1);
+ break;
+ case 0x5: /* LDX.UW */
+ error = misaligned_load(regs, opcode, 0, 1, 0);
+ break;
+ case 0x2: /* LDX.L */
+ error = misaligned_load(regs, opcode, 0, 2, 1);
+ break;
+ case 0x3: /* LDX.Q */
+ error = misaligned_load(regs, opcode, 0, 3, 0);
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ break;
+
+ case (0x60>>2): /* indexed stores */
+ switch (minor) {
+ case 0x1: /* STX.W */
+ error = misaligned_store(regs, opcode, 0, 1);
+ break;
+ case 0x2: /* STX.L */
+ error = misaligned_store(regs, opcode, 0, 2);
+ break;
+ case 0x3: /* STX.Q */
+ error = misaligned_store(regs, opcode, 0, 3);
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ break;
+
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ case (0x94>>2): /* FLD.S */
+ error = misaligned_fpu_load(regs, opcode, 1, 2, 0);
+ break;
+ case (0x98>>2): /* FLD.P */
+ error = misaligned_fpu_load(regs, opcode, 1, 3, 1);
+ break;
+ case (0x9c>>2): /* FLD.D */
+ error = misaligned_fpu_load(regs, opcode, 1, 3, 0);
+ break;
+ case (0x1c>>2): /* floating indexed loads */
+ switch (minor) {
+ case 0x8: /* FLDX.S */
+ error = misaligned_fpu_load(regs, opcode, 0, 2, 0);
+ break;
+ case 0xd: /* FLDX.P */
+ error = misaligned_fpu_load(regs, opcode, 0, 3, 1);
+ break;
+ case 0x9: /* FLDX.D */
+ error = misaligned_fpu_load(regs, opcode, 0, 3, 0);
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ break;
+ case (0xb4>>2): /* FLD.S */
+ error = misaligned_fpu_store(regs, opcode, 1, 2, 0);
+ break;
+ case (0xb8>>2): /* FLD.P */
+ error = misaligned_fpu_store(regs, opcode, 1, 3, 1);
+ break;
+ case (0xbc>>2): /* FLD.D */
+ error = misaligned_fpu_store(regs, opcode, 1, 3, 0);
+ break;
+ case (0x3c>>2): /* floating indexed stores */
+ switch (minor) {
+ case 0x8: /* FSTX.S */
+ error = misaligned_fpu_store(regs, opcode, 0, 2, 0);
+ break;
+ case 0xd: /* FSTX.P */
+ error = misaligned_fpu_store(regs, opcode, 0, 3, 1);
+ break;
+ case 0x9: /* FSTX.D */
+ error = misaligned_fpu_store(regs, opcode, 0, 3, 0);
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ break;
+#endif
+
+ default:
+ /* Fault */
+ error = -1;
+ break;
+ }
+
+ if (error < 0) {
+ return error;
+ } else {
+ regs->pc += 4; /* Skip the instruction that's just been emulated */
+ return 0;
+ }
+
+}
+
+static ctl_table unaligned_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "kernel_reports",
+ .data = &kernel_mode_unaligned_fixup_count,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "user_reports",
+ .data = &user_mode_unaligned_fixup_count,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "user_enable",
+ .data = &user_mode_unaligned_fixup_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec},
+#endif
+ {}
+};
+
+static ctl_table unaligned_root[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "unaligned_fixup",
+ .mode = 0555,
+ unaligned_table
+ },
+ {}
+};
+
+static ctl_table sh64_root[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "sh64",
+ .mode = 0555,
+ .child = unaligned_root
+ },
+ {}
+};
+static struct ctl_table_header *sysctl_header;
+static int __init init_sysctl(void)
+{
+ sysctl_header = register_sysctl_table(sh64_root);
+ return 0;
+}
+
+__initcall(init_sysctl);
+
+
+asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)
+{
+ u64 peek_real_address_q(u64 addr);
+ u64 poke_real_address_q(u64 addr, u64 val);
+ unsigned long long DM_EXP_CAUSE_PHY = 0x0c100010;
+ unsigned long long exp_cause;
+ /* It's not worth ioremapping the debug module registers for the amount
+ of access we make to them - just go direct to their physical
+ addresses. */
+ exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY);
+ if (exp_cause & ~4) {
+ printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n",
+ (unsigned long)(exp_cause & 0xffffffff));
+ }
+ show_state();
+ /* Clear all DEBUGINT causes */
+ poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0);
+}
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 0956fb3681a3..d7d4991f32af 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -1,138 +1,5 @@
-/*
- * ld script to make SuperH Linux kernel
- * Written by Niibe Yutaka
- */
-#include <asm/thread_info.h>
-#include <asm/cache.h>
-#include <asm-generic/vmlinux.lds.h>
-
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+#ifdef CONFIG_SUPERH32
+# include "vmlinux_32.lds.S"
#else
-OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
+# include "vmlinux_64.lds.S"
#endif
-OUTPUT_ARCH(sh)
-ENTRY(_start)
-SECTIONS
-{
- . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
- _text = .; /* Text and read-only data */
-
- .empty_zero_page : {
- *(.empty_zero_page)
- } = 0
-
- .text : {
- *(.text.head)
- TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.fixup)
- *(.gnu.warning)
- } = 0x0009
-
- . = ALIGN(16); /* Exception table */
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
- _etext = .; /* End of text section */
-
- BUG_TABLE
- NOTES
- RO_DATA(PAGE_SIZE)
-
- . = ALIGN(THREAD_SIZE);
- .data : { /* Data */
- *(.data.init_task)
-
- . = ALIGN(L1_CACHE_BYTES);
- *(.data.cacheline_aligned)
-
- . = ALIGN(L1_CACHE_BYTES);
- *(.data.read_mostly)
-
- . = ALIGN(PAGE_SIZE);
- *(.data.page_aligned)
-
- __nosave_begin = .;
- *(.data.nosave)
- . = ALIGN(PAGE_SIZE);
- __nosave_end = .;
-
- DATA_DATA
- CONSTRUCTORS
- }
-
- _edata = .; /* End of data section */
-
- . = ALIGN(PAGE_SIZE); /* Init code and data */
- __init_begin = .;
- _sinittext = .;
- .init.text : { *(.init.text) }
- _einittext = .;
- .init.data : { *(.init.data) }
-
- . = ALIGN(16);
- __setup_start = .;
- .init.setup : { *(.init.setup) }
- __setup_end = .;
-
- __initcall_start = .;
- .initcall.init : {
- INITCALLS
- }
- __initcall_end = .;
- __con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
- __con_initcall_end = .;
-
- SECURITY_INIT
-
-#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(PAGE_SIZE);
- __initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
- __initramfs_end = .;
-#endif
-
- . = ALIGN(4);
- __machvec_start = .;
- .machvec.init : { *(.machvec.init) }
- __machvec_end = .;
-
- PERCPU(PAGE_SIZE)
-
- /*
- * .exit.text is discarded at runtime, not link time, to deal with
- * references from __bug_table
- */
- .exit.text : { *(.exit.text) }
- .exit.data : { *(.exit.data) }
-
- . = ALIGN(PAGE_SIZE);
- .bss : {
- __init_end = .;
- __bss_start = .; /* BSS */
- *(.bss.page_aligned)
- *(.bss)
- *(COMMON)
- . = ALIGN(4);
- _ebss = .; /* uClinux MTD sucks */
- _end = . ;
- }
-
- /*
- * When something in the kernel is NOT compiled as a module, the
- * module cleanup code and data are put into these segments. Both
- * can then be thrown away, as cleanup code is never called unless
- * it's a module.
- */
- /DISCARD/ : {
- *(.exitcall.exit)
- }
-
- STABS_DEBUG
- DWARF_DEBUG
-}
diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S
new file mode 100644
index 000000000000..d549fac6d3e7
--- /dev/null
+++ b/arch/sh/kernel/vmlinux_32.lds.S
@@ -0,0 +1,152 @@
+/*
+ * ld script to make SuperH Linux kernel
+ * Written by Niibe Yutaka
+ */
+#include <asm/thread_info.h>
+#include <asm/cache.h>
+#include <asm-generic/vmlinux.lds.h>
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+#else
+OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
+#endif
+OUTPUT_ARCH(sh)
+ENTRY(_start)
+SECTIONS
+{
+#ifdef CONFIG_32BIT
+ . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
+#else
+ . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+#endif
+
+ _text = .; /* Text and read-only data */
+
+ .empty_zero_page : {
+ *(.empty_zero_page)
+ } = 0
+
+ .text : {
+ *(.text.head)
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+ } = 0x0009
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ _etext = .; /* End of text section */
+
+ BUG_TABLE
+ NOTES
+ RO_DATA(PAGE_SIZE)
+
+ /*
+ * Code which must be executed uncached and the associated data
+ */
+ . = ALIGN(PAGE_SIZE);
+ __uncached_start = .;
+ .uncached.text : { *(.uncached.text) }
+ .uncached.data : { *(.uncached.data) }
+ __uncached_end = .;
+
+ . = ALIGN(THREAD_SIZE);
+ .data : { /* Data */
+ *(.data.init_task)
+
+ . = ALIGN(L1_CACHE_BYTES);
+ *(.data.cacheline_aligned)
+
+ . = ALIGN(L1_CACHE_BYTES);
+ *(.data.read_mostly)
+
+ . = ALIGN(PAGE_SIZE);
+ *(.data.page_aligned)
+
+ __nosave_begin = .;
+ *(.data.nosave)
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
+
+ DATA_DATA
+ CONSTRUCTORS
+ }
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(PAGE_SIZE); /* Init code and data */
+ __init_begin = .;
+ _sinittext = .;
+ .init.text : { *(.init.text) }
+ _einittext = .;
+ .init.data : { *(.init.data) }
+
+ . = ALIGN(16);
+ __setup_start = .;
+ .init.setup : { *(.init.setup) }
+ __setup_end = .;
+
+ __initcall_start = .;
+ .initcall.init : {
+ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
+
+ SECURITY_INIT
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(PAGE_SIZE);
+ __initramfs_start = .;
+ .init.ramfs : { *(.init.ramfs) }
+ __initramfs_end = .;
+#endif
+
+ . = ALIGN(4);
+ __machvec_start = .;
+ .machvec.init : { *(.machvec.init) }
+ __machvec_end = .;
+
+ PERCPU(PAGE_SIZE)
+
+ /*
+ * .exit.text is discarded at runtime, not link time, to deal with
+ * references from __bug_table
+ */
+ .exit.text : { *(.exit.text) }
+ .exit.data : { *(.exit.data) }
+
+ . = ALIGN(PAGE_SIZE);
+ .bss : {
+ __init_end = .;
+ __bss_start = .; /* BSS */
+ *(.bss.page_aligned)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .; /* uClinux MTD sucks */
+ _end = . ;
+ }
+
+ /*
+ * When something in the kernel is NOT compiled as a module, the
+ * module cleanup code and data are put into these segments. Both
+ * can then be thrown away, as cleanup code is never called unless
+ * it's a module.
+ */
+ /DISCARD/ : {
+ *(.exitcall.exit)
+ }
+
+ STABS_DEBUG
+ DWARF_DEBUG
+}
diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S
new file mode 100644
index 000000000000..2fd0f7401484
--- /dev/null
+++ b/arch/sh/kernel/vmlinux_64.lds.S
@@ -0,0 +1,164 @@
+/*
+ * ld script to make SH64 Linux kernel
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * benedict.gaster@superh.com: 2nd May 2002
+ * Add definition of empty_zero_page to be the first page of kernel image.
+ *
+ * benedict.gaster@superh.com: 3rd May 2002
+ * Added support for ramdisk, removing statically linked romfs at the
+ * same time.
+ *
+ * lethal@linux-sh.org: 9th May 2003
+ * Kill off GLOBAL_NAME() usage and other CDC-isms.
+ *
+ * lethal@linux-sh.org: 19th May 2003
+ * Remove support for ancient toolchains.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+
+#define LOAD_OFFSET CONFIG_PAGE_OFFSET
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_ARCH(sh:sh5)
+
+#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
+
+ENTRY(__start)
+SECTIONS
+{
+ . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE;
+ _text = .; /* Text and read-only data */
+
+ .empty_zero_page : C_PHYS(.empty_zero_page) {
+ *(.empty_zero_page)
+ } = 0
+
+ .text : C_PHYS(.text) {
+ *(.text.head)
+ TEXT_TEXT
+ *(.text64)
+ *(.text..SHmedia32)
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+#ifdef CONFIG_LITTLE_ENDIAN
+ } = 0x6ff0fff0
+#else
+ } = 0xf0fff06f
+#endif
+
+ /* We likely want __ex_table to be Cache Line aligned */
+ . = ALIGN(L1_CACHE_BYTES); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : C_PHYS(__ex_table) { *(__ex_table) }
+ __stop___ex_table = .;
+
+ _etext = .; /* End of text section */
+
+ BUG_TABLE
+ NOTES
+ RO_DATA(PAGE_SIZE)
+
+ . = ALIGN(THREAD_SIZE);
+ .data : C_PHYS(.data) { /* Data */
+ *(.data.init_task)
+
+ . = ALIGN(L1_CACHE_BYTES);
+ *(.data.cacheline_aligned)
+
+ . = ALIGN(L1_CACHE_BYTES);
+ *(.data.read_mostly)
+
+ . = ALIGN(PAGE_SIZE);
+ *(.data.page_aligned)
+
+ __nosave_begin = .;
+ *(.data.nosave)
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
+
+ DATA_DATA
+ CONSTRUCTORS
+ }
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(PAGE_SIZE); /* Init code and data */
+ __init_begin = .;
+ _sinittext = .;
+ .init.text : C_PHYS(.init.text) { *(.init.text) }
+ _einittext = .;
+ .init.data : C_PHYS(.init.data) { *(.init.data) }
+ . = ALIGN(L1_CACHE_BYTES); /* Better if Cache Line aligned */
+ __setup_start = .;
+ .init.setup : C_PHYS(.init.setup) { *(.init.setup) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : C_PHYS(.initcall.init) {
+ INITCALLS
+ }
+ __initcall_end = .;
+ __con_initcall_start = .;
+ .con_initcall.init : C_PHYS(.con_initcall.init) {
+ *(.con_initcall.init)
+ }
+ __con_initcall_end = .;
+
+ SECURITY_INIT
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(PAGE_SIZE);
+ __initramfs_start = .;
+ .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) }
+ __initramfs_end = .;
+#endif
+
+ . = ALIGN(8);
+ __machvec_start = .;
+ .machvec.init : C_PHYS(.machvec.init) { *(.machvec.init) }
+ __machvec_end = .;
+
+ PERCPU(PAGE_SIZE)
+
+ /*
+ * .exit.text is discarded at runtime, not link time, to deal with
+ * references from __bug_table
+ */
+ .exit.text : C_PHYS(.exit.text) { *(.exit.text) }
+ .exit.data : C_PHYS(.exit.data) { *(.exit.data) }
+
+ . = ALIGN(PAGE_SIZE);
+ .bss : C_PHYS(.bss) {
+ __init_end = .;
+ __bss_start = .; /* BSS */
+ *(.bss.page_aligned)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .; /* uClinux MTD sucks */
+ _end = . ;
+ }
+
+ /*
+ * When something in the kernel is NOT compiled as a module, the
+ * module cleanup code and data are put into these segments. Both
+ * can then be thrown away, as cleanup code is never called unless
+ * it's a module.
+ */
+ /DISCARD/ : {
+ *(.exitcall.exit)
+ }
+
+ STABS_DEBUG
+ DWARF_DEBUG
+}
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index 9dc7b6985052..ebb55d1149f5 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -2,12 +2,13 @@
# Makefile for SuperH-specific library files..
#
-lib-y = delay.o memset.o memmove.o memchr.o \
+lib-y = delay.o io.o memset.o memmove.o memchr.o \
checksum.o strlen.o div64.o div64-generic.o
memcpy-y := memcpy.o
memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o
-lib-y += $(memcpy-y)
+lib-$(CONFIG_MMU) += copy_page.o clear_page.o
+lib-y += $(memcpy-y)
EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/mm/clear_page.S b/arch/sh/lib/clear_page.S
index 7a7c81ee3f01..3539123fe517 100644
--- a/arch/sh/mm/clear_page.S
+++ b/arch/sh/lib/clear_page.S
@@ -9,10 +9,10 @@
#include <asm/page.h>
/*
- * clear_page_slow
+ * clear_page
* @to: P1 address
*
- * void clear_page_slow(void *to)
+ * void clear_page(void *to)
*/
/*
@@ -20,7 +20,7 @@
* r4 --- to
* r5 --- to + PAGE_SIZE
*/
-ENTRY(clear_page_slow)
+ENTRY(clear_page)
mov r4,r5
mov.l .Llimit,r0
add r0,r5
@@ -50,6 +50,8 @@ ENTRY(clear_page_slow)
!
rts
nop
+
+ .balign 4
.Llimit: .long (PAGE_SIZE-28)
ENTRY(__clear_user)
diff --git a/arch/sh/mm/copy_page.S b/arch/sh/lib/copy_page.S
index 40685018b952..e002b91c8752 100644
--- a/arch/sh/mm/copy_page.S
+++ b/arch/sh/lib/copy_page.S
@@ -9,11 +9,11 @@
#include <asm/page.h>
/*
- * copy_page_slow
+ * copy_page
* @to: P1 address
* @from: P1 address
*
- * void copy_page_slow(void *to, void *from)
+ * void copy_page(void *to, void *from)
*/
/*
@@ -23,7 +23,7 @@
* r10 --- to
* r11 --- from
*/
-ENTRY(copy_page_slow)
+ENTRY(copy_page)
mov.l r8,@-r15
mov.l r10,@-r15
mov.l r11,@-r15
@@ -68,8 +68,9 @@ ENTRY(copy_page_slow)
rts
nop
- .align 2
+ .balign 4
.Lpsz: .long PAGE_SIZE
+
/*
* __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
* Return the number of bytes NOT copied
diff --git a/arch/sh/lib/io.c b/arch/sh/lib/io.c
new file mode 100644
index 000000000000..4f54ec43516f
--- /dev/null
+++ b/arch/sh/lib/io.c
@@ -0,0 +1,82 @@
+/*
+ * arch/sh/lib/io.c - SH32 optimized I/O routines
+ *
+ * Copyright (C) 2000 Stuart Menefy
+ * Copyright (C) 2005 Paul Mundt
+ *
+ * Provide real functions which expand to whatever the header file defined.
+ * Also definitions of machine independent IO functions.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+
+void __raw_readsl(unsigned long addr, void *datap, int len)
+{
+ u32 *data;
+
+ for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
+ *data++ = ctrl_inl(addr);
+
+ if (likely(len >= (0x20 >> 2))) {
+ int tmp2, tmp3, tmp4, tmp5, tmp6;
+
+ __asm__ __volatile__(
+ "1: \n\t"
+ "mov.l @%7, r0 \n\t"
+ "mov.l @%7, %2 \n\t"
+#ifdef CONFIG_CPU_SH4
+ "movca.l r0, @%0 \n\t"
+#else
+ "mov.l r0, @%0 \n\t"
+#endif
+ "mov.l @%7, %3 \n\t"
+ "mov.l @%7, %4 \n\t"
+ "mov.l @%7, %5 \n\t"
+ "mov.l @%7, %6 \n\t"
+ "mov.l @%7, r7 \n\t"
+ "mov.l @%7, r0 \n\t"
+ "mov.l %2, @(0x04,%0) \n\t"
+ "mov #0x20>>2, %2 \n\t"
+ "mov.l %3, @(0x08,%0) \n\t"
+ "sub %2, %1 \n\t"
+ "mov.l %4, @(0x0c,%0) \n\t"
+ "cmp/hi %1, %2 ! T if 32 > len \n\t"
+ "mov.l %5, @(0x10,%0) \n\t"
+ "mov.l %6, @(0x14,%0) \n\t"
+ "mov.l r7, @(0x18,%0) \n\t"
+ "mov.l r0, @(0x1c,%0) \n\t"
+ "bf.s 1b \n\t"
+ " add #0x20, %0 \n\t"
+ : "=&r" (data), "=&r" (len),
+ "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
+ "=&r" (tmp5), "=&r" (tmp6)
+ : "r"(addr), "0" (data), "1" (len)
+ : "r0", "r7", "t", "memory");
+ }
+
+ for (; len != 0; len--)
+ *data++ = ctrl_inl(addr);
+}
+EXPORT_SYMBOL(__raw_readsl);
+
+void __raw_writesl(unsigned long addr, const void *data, int len)
+{
+ if (likely(len != 0)) {
+ int tmp1;
+
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "mov.l @%0+, %1 \n\t"
+ "dt %3 \n\t"
+ "bf.s 1b \n\t"
+ " mov.l %1, @%4 \n\t"
+ : "=&r" (data), "=&r" (tmp1)
+ : "0" (data), "r" (len), "r"(addr)
+ : "t", "memory");
+ }
+}
+EXPORT_SYMBOL(__raw_writesl);
diff --git a/arch/sh/lib64/.gitignore b/arch/sh/lib64/.gitignore
new file mode 100644
index 000000000000..3508c2cb23c4
--- /dev/null
+++ b/arch/sh/lib64/.gitignore
@@ -0,0 +1 @@
+syscalltab.h
diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile
new file mode 100644
index 000000000000..9950966923a0
--- /dev/null
+++ b/arch/sh/lib64/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the SH-5 specific library files..
+#
+# Copyright (C) 2000, 2001 Paolo Alberelli
+# Copyright (C) 2003 Paul Mundt
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+# Panic should really be compiled as PIC
+lib-y := udelay.o c-checksum.o dbg.o panic.o memcpy.o copy_user_memcpy.o \
+ copy_page.o clear_page.o
+
diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c
new file mode 100644
index 000000000000..5dfbd8b5e558
--- /dev/null
+++ b/arch/sh/lib64/c-checksum.c
@@ -0,0 +1,214 @@
+/*
+ * arch/sh/lib64/c-checksum.c
+ *
+ * This file contains network checksum routines that are better done
+ * in an architecture-specific manner due to speed..
+ */
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+static inline unsigned short from64to16(unsigned long long x)
+{
+ /* add up 32-bit words for 33 bits */
+ x = (x & 0xffffffff) + (x >> 32);
+ /* add up 16-bit and 17-bit words for 17+c bits */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up 16-bit and 2-bit for 16+c bit */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up carry.. */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+static inline unsigned short foldto16(unsigned long x)
+{
+ /* add up 16-bit for 17 bits */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up carry.. */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+static inline unsigned short myfoldto16(unsigned long long x)
+{
+ /* Fold down to 32-bits so we don't loose in the typedef-less
+ network stack. */
+ /* 64 to 33 */
+ x = (x & 0xffffffff) + (x >> 32);
+ /* 33 to 32 */
+ x = (x & 0xffffffff) + (x >> 32);
+
+ /* add up 16-bit for 17 bits */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up carry.. */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+#define odd(x) ((x)&1)
+#define U16(x) ntohs(x)
+
+static unsigned long do_csum(const unsigned char *buff, int len)
+{
+ int odd, count;
+ unsigned long result = 0;
+
+ pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
+#ifdef DEBUG
+ for (i = 0; i < len; i++) {
+ if ((i % 26) == 0)
+ printk("\n");
+ printk("%02X ", buff[i]);
+ }
+#endif
+
+ if (len <= 0)
+ goto out;
+
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+ result = *buff << 8;
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(unsigned short *) buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+ unsigned long carry = 0;
+ do {
+ unsigned long w = *(unsigned long *) buff;
+ buff += 4;
+ count--;
+ result += carry;
+ result += w;
+ carry = (w > result);
+ } while (count);
+ result += carry;
+ result = (result & 0xffff) + (result >> 16);
+ }
+ if (len & 2) {
+ result += *(unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+ result += *buff;
+ result = foldto16(result);
+ if (odd)
+ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+
+ pr_debug("\nCHECKSUM is 0x%lx\n", result);
+
+ out:
+ return result;
+}
+
+/* computes the checksum of a memory block at buff, length len,
+ and adds in "sum" (32-bit) */
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+ unsigned long long result = do_csum(buff, len);
+
+ /* add in old sum, and carry.. */
+ result += (__force u32)sum;
+ /* 32+c bits -> 32 bits */
+ result = (result & 0xffffffff) + (result >> 32);
+
+ pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
+ buff, len, sum, result);
+
+ return (__force __wsum)result;
+}
+
+/* Copy while checksumming, otherwise like csum_partial. */
+__wsum
+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+{
+ sum = csum_partial(src, len, sum);
+ memcpy(dst, src, len);
+
+ return sum;
+}
+
+/* Copy from userspace and compute checksum. If we catch an exception
+ then zero the rest of the buffer. */
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+ __wsum sum, int *err_ptr)
+{
+ int missing;
+
+ pr_debug
+ ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
+ src, dst, len, sum, err_ptr);
+ missing = copy_from_user(dst, src, len);
+ pr_debug(" access_ok %d\n", __access_ok((unsigned long) src, len));
+ pr_debug(" missing %d\n", missing);
+ if (missing) {
+ memset(dst + len - missing, 0, missing);
+ *err_ptr = -EFAULT;
+ }
+
+ return csum_partial(dst, len, sum);
+}
+
+/* Copy to userspace and compute checksum. */
+__wsum
+csum_partial_copy_to_user(const unsigned char *src, unsigned char *dst, int len,
+ __wsum sum, int *err_ptr)
+{
+ sum = csum_partial(src, len, sum);
+
+ if (copy_to_user(dst, src, len))
+ *err_ptr = -EFAULT;
+
+ return sum;
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ pr_debug("ip_fast_csum %p,%d\n", iph, ihl);
+
+ return (__force __sum16)~do_csum(iph, ihl * 4);
+}
+
+__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto, __wsum sum)
+{
+ unsigned long long result;
+
+ pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
+ pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
+
+ result = (__force u64) saddr + (__force u64) daddr +
+ (__force u64) sum + ((len + proto) << 8);
+
+ /* Fold down to 32-bits so we don't loose in the typedef-less
+ network stack. */
+ /* 64 to 33 */
+ result = (result & 0xffffffff) + (result >> 32);
+ /* 33 to 32 */
+ result = (result & 0xffffffff) + (result >> 32);
+
+ pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
+ __FUNCTION__, saddr, daddr, len, proto, sum, result);
+
+ return (__wsum)result;
+}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
diff --git a/arch/sh/lib64/clear_page.S b/arch/sh/lib64/clear_page.S
new file mode 100644
index 000000000000..007ab48ecc1c
--- /dev/null
+++ b/arch/sh/lib64/clear_page.S
@@ -0,0 +1,54 @@
+/*
+ Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
+
+ This file is subject to the terms and conditions of the GNU General Public
+ License. See the file "COPYING" in the main directory of this archive
+ for more details.
+
+ Tight version of memset for the case of just clearing a page. It turns out
+ that having the alloco's spaced out slightly due to the increment/branch
+ pair causes them to contend less for access to the cache. Similarly,
+ keeping the stores apart from the allocos causes less contention. => Do two
+ separate loops. Do multiple stores per loop to amortise the
+ increment/branch cost a little.
+
+ Parameters:
+ r2 : source effective address (start of page)
+
+ Always clears 4096 bytes.
+
+ Note : alloco guarded by synco to avoid TAKum03020 erratum
+
+*/
+
+ .section .text..SHmedia32,"ax"
+ .little
+
+ .balign 8
+ .global clear_page
+clear_page:
+ pta/l 1f, tr1
+ pta/l 2f, tr2
+ ptabs/l r18, tr0
+
+ movi 4096, r7
+ add r2, r7, r7
+ add r2, r63, r6
+1:
+ alloco r6, 0
+ synco ! TAKum03020
+ addi r6, 32, r6
+ bgt/l r7, r6, tr1
+
+ add r2, r63, r6
+2:
+ st.q r6, 0, r63
+ st.q r6, 8, r63
+ st.q r6, 16, r63
+ st.q r6, 24, r63
+ addi r6, 32, r6
+ bgt/l r7, r6, tr2
+
+ blink tr0, r63
+
+
diff --git a/arch/sh/lib64/copy_page.S b/arch/sh/lib64/copy_page.S
new file mode 100644
index 000000000000..0ec6fca63b56
--- /dev/null
+++ b/arch/sh/lib64/copy_page.S
@@ -0,0 +1,89 @@
+/*
+ Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
+
+ This file is subject to the terms and conditions of the GNU General Public
+ License. See the file "COPYING" in the main directory of this archive
+ for more details.
+
+ Tight version of mempy for the case of just copying a page.
+ Prefetch strategy empirically optimised against RTL simulations
+ of SH5-101 cut2 eval chip with Cayman board DDR memory.
+
+ Parameters:
+ r2 : destination effective address (start of page)
+ r3 : source effective address (start of page)
+
+ Always copies 4096 bytes.
+
+ Points to review.
+ * Currently the prefetch is 4 lines ahead and the alloco is 2 lines ahead.
+ It seems like the prefetch needs to be at at least 4 lines ahead to get
+ the data into the cache in time, and the allocos contend with outstanding
+ prefetches for the same cache set, so it's better to have the numbers
+ different.
+ */
+
+ .section .text..SHmedia32,"ax"
+ .little
+
+ .balign 8
+ .global copy_page
+copy_page:
+
+ /* Copy 4096 bytes worth of data from r3 to r2.
+ Do prefetches 4 lines ahead.
+ Do alloco 2 lines ahead */
+
+ pta 1f, tr1
+ pta 2f, tr2
+ pta 3f, tr3
+ ptabs r18, tr0
+
+#if 0
+ /* TAKum03020 */
+ ld.q r3, 0x00, r63
+ ld.q r3, 0x20, r63
+ ld.q r3, 0x40, r63
+ ld.q r3, 0x60, r63
+#endif
+ alloco r2, 0x00
+ synco ! TAKum03020
+ alloco r2, 0x20
+ synco ! TAKum03020
+
+ movi 3968, r6
+ add r2, r6, r6
+ addi r6, 64, r7
+ addi r7, 64, r8
+ sub r3, r2, r60
+ addi r60, 8, r61
+ addi r61, 8, r62
+ addi r62, 8, r23
+ addi r60, 0x80, r22
+
+/* Minimal code size. The extra branches inside the loop don't cost much
+ because they overlap with the time spent waiting for prefetches to
+ complete. */
+1:
+#if 0
+ /* TAKum03020 */
+ bge/u r2, r6, tr2 ! skip prefetch for last 4 lines
+ ldx.q r2, r22, r63 ! prefetch 4 lines hence
+#endif
+2:
+ bge/u r2, r7, tr3 ! skip alloco for last 2 lines
+ alloco r2, 0x40 ! alloc destination line 2 lines ahead
+ synco ! TAKum03020
+3:
+ ldx.q r2, r60, r36
+ ldx.q r2, r61, r37
+ ldx.q r2, r62, r38
+ ldx.q r2, r23, r39
+ st.q r2, 0, r36
+ st.q r2, 8, r37
+ st.q r2, 16, r38
+ st.q r2, 24, r39
+ addi r2, 32, r2
+ bgt/l r8, r2, tr1
+
+ blink tr0, r63 ! return
diff --git a/arch/sh/lib64/copy_user_memcpy.S b/arch/sh/lib64/copy_user_memcpy.S
new file mode 100644
index 000000000000..2a62816d2ddd
--- /dev/null
+++ b/arch/sh/lib64/copy_user_memcpy.S
@@ -0,0 +1,217 @@
+!
+! Fast SH memcpy
+!
+! by Toshiyasu Morita (tm@netcom.com)
+! hacked by J"orn Rernnecke (joern.rennecke@superh.com) ("o for o-umlaut)
+! SH5 code Copyright 2002 SuperH Ltd.
+!
+! Entry: ARG0: destination pointer
+! ARG1: source pointer
+! ARG2: byte count
+!
+! Exit: RESULT: destination pointer
+! any other registers in the range r0-r7: trashed
+!
+! Notes: Usually one wants to do small reads and write a longword, but
+! unfortunately it is difficult in some cases to concatanate bytes
+! into a longword on the SH, so this does a longword read and small
+! writes.
+!
+! This implementation makes two assumptions about how it is called:
+!
+! 1.: If the byte count is nonzero, the address of the last byte to be
+! copied is unsigned greater than the address of the first byte to
+! be copied. This could be easily swapped for a signed comparison,
+! but the algorithm used needs some comparison.
+!
+! 2.: When there are two or three bytes in the last word of an 11-or-more
+! bytes memory chunk to b copied, the rest of the word can be read
+! without side effects.
+! This could be easily changed by increasing the minumum size of
+! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
+! however, this would cost a few extra cyles on average.
+! For SHmedia, the assumption is that any quadword can be read in its
+! enirety if at least one byte is included in the copy.
+
+/* Imported into Linux kernel by Richard Curnow. This is used to implement the
+ __copy_user function in the general case, so it has to be a distinct
+ function from intra-kernel memcpy to allow for exception fix-ups in the
+ event that the user pointer is bad somewhere in the copy (e.g. due to
+ running off the end of the vma).
+
+ Note, this algorithm will be slightly wasteful in the case where the source
+ and destination pointers are equally aligned, because the stlo/sthi pairs
+ could then be merged back into single stores. If there are a lot of cache
+ misses, this is probably offset by the stall lengths on the preloads.
+
+*/
+
+/* NOTE : Prefetches removed and allocos guarded by synco to avoid TAKum03020
+ * erratum. The first two prefetches are nop-ed out to avoid upsetting the
+ * instruction counts used in the jump address calculation.
+ * */
+
+ .section .text..SHmedia32,"ax"
+ .little
+ .balign 32
+ .global copy_user_memcpy
+ .global copy_user_memcpy_end
+copy_user_memcpy:
+
+#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1
+#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1
+#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1
+#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1
+
+ nop ! ld.b r3,0,r63 ! TAKum03020
+ pta/l Large,tr0
+ movi 25,r0
+ bgeu/u r4,r0,tr0
+ nsb r4,r0
+ shlli r0,5,r0
+ movi (L1-L0+63*32 + 1) & 0xffff,r1
+ sub r1, r0, r0
+L0: ptrel r0,tr0
+ add r2,r4,r5
+ ptabs r18,tr1
+ add r3,r4,r6
+ blink tr0,r63
+
+/* Rearranged to make cut2 safe */
+ .balign 8
+L4_7: /* 4..7 byte memcpy cntd. */
+ stlo.l r2, 0, r0
+ or r6, r7, r6
+ sthi.l r5, -1, r6
+ stlo.l r5, -4, r6
+ blink tr1,r63
+
+ .balign 8
+L1: /* 0 byte memcpy */
+ nop
+ blink tr1,r63
+ nop
+ nop
+ nop
+ nop
+
+L2_3: /* 2 or 3 byte memcpy cntd. */
+ st.b r5,-1,r6
+ blink tr1,r63
+
+ /* 1 byte memcpy */
+ ld.b r3,0,r0
+ st.b r2,0,r0
+ blink tr1,r63
+
+L8_15: /* 8..15 byte memcpy cntd. */
+ stlo.q r2, 0, r0
+ or r6, r7, r6
+ sthi.q r5, -1, r6
+ stlo.q r5, -8, r6
+ blink tr1,r63
+
+ /* 2 or 3 byte memcpy */
+ ld.b r3,0,r0
+ nop ! ld.b r2,0,r63 ! TAKum03020
+ ld.b r3,1,r1
+ st.b r2,0,r0
+ pta/l L2_3,tr0
+ ld.b r6,-1,r6
+ st.b r2,1,r1
+ blink tr0, r63
+
+ /* 4 .. 7 byte memcpy */
+ LDUAL (r3, 0, r0, r1)
+ pta L4_7, tr0
+ ldlo.l r6, -4, r7
+ or r0, r1, r0
+ sthi.l r2, 3, r0
+ ldhi.l r6, -1, r6
+ blink tr0, r63
+
+ /* 8 .. 15 byte memcpy */
+ LDUAQ (r3, 0, r0, r1)
+ pta L8_15, tr0
+ ldlo.q r6, -8, r7
+ or r0, r1, r0
+ sthi.q r2, 7, r0
+ ldhi.q r6, -1, r6
+ blink tr0, r63
+
+ /* 16 .. 24 byte memcpy */
+ LDUAQ (r3, 0, r0, r1)
+ LDUAQ (r3, 8, r8, r9)
+ or r0, r1, r0
+ sthi.q r2, 7, r0
+ or r8, r9, r8
+ sthi.q r2, 15, r8
+ ldlo.q r6, -8, r7
+ ldhi.q r6, -1, r6
+ stlo.q r2, 8, r8
+ stlo.q r2, 0, r0
+ or r6, r7, r6
+ sthi.q r5, -1, r6
+ stlo.q r5, -8, r6
+ blink tr1,r63
+
+Large:
+ ! ld.b r2, 0, r63 ! TAKum03020
+ pta/l Loop_ua, tr1
+ ori r3, -8, r7
+ sub r2, r7, r22
+ sub r3, r2, r6
+ add r2, r4, r5
+ ldlo.q r3, 0, r0
+ addi r5, -16, r5
+ movi 64+8, r27 ! could subtract r7 from that.
+ stlo.q r2, 0, r0
+ sthi.q r2, 7, r0
+ ldx.q r22, r6, r0
+ bgtu/l r27, r4, tr1
+
+ addi r5, -48, r27
+ pta/l Loop_line, tr0
+ addi r6, 64, r36
+ addi r6, -24, r19
+ addi r6, -16, r20
+ addi r6, -8, r21
+
+Loop_line:
+ ! ldx.q r22, r36, r63 ! TAKum03020
+ alloco r22, 32
+ synco
+ addi r22, 32, r22
+ ldx.q r22, r19, r23
+ sthi.q r22, -25, r0
+ ldx.q r22, r20, r24
+ ldx.q r22, r21, r25
+ stlo.q r22, -32, r0
+ ldx.q r22, r6, r0
+ sthi.q r22, -17, r23
+ sthi.q r22, -9, r24
+ sthi.q r22, -1, r25
+ stlo.q r22, -24, r23
+ stlo.q r22, -16, r24
+ stlo.q r22, -8, r25
+ bgeu r27, r22, tr0
+
+Loop_ua:
+ addi r22, 8, r22
+ sthi.q r22, -1, r0
+ stlo.q r22, -8, r0
+ ldx.q r22, r6, r0
+ bgtu/l r5, r22, tr1
+
+ add r3, r4, r7
+ ldlo.q r7, -8, r1
+ sthi.q r22, 7, r0
+ ldhi.q r7, -1, r7
+ ptabs r18,tr1
+ stlo.q r22, 0, r0
+ or r1, r7, r1
+ sthi.q r5, 15, r1
+ stlo.q r5, 8, r1
+ blink tr1, r63
+copy_user_memcpy_end:
+ nop
diff --git a/arch/sh/lib64/dbg.c b/arch/sh/lib64/dbg.c
new file mode 100644
index 000000000000..75825ef6e084
--- /dev/null
+++ b/arch/sh/lib64/dbg.c
@@ -0,0 +1,430 @@
+/*--------------------------------------------------------------------------
+--
+-- Identity : Linux50 Debug Funcions
+--
+-- File : arch/sh/lib64/dbg.c
+--
+-- Copyright 2000, 2001 STMicroelectronics Limited.
+-- Copyright 2004 Richard Curnow (evt_debug etc)
+--
+--------------------------------------------------------------------------*/
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <asm/mmu_context.h>
+
+typedef u64 regType_t;
+
+static regType_t getConfigReg(u64 id)
+{
+ register u64 reg __asm__("r2");
+ asm volatile ("getcfg %1, 0, %0":"=r" (reg):"r"(id));
+ return (reg);
+}
+
+/* ======================================================================= */
+
+static char *szTab[] = { "4k", "64k", "1M", "512M" };
+static char *protTab[] = { "----",
+ "---R",
+ "--X-",
+ "--XR",
+ "-W--",
+ "-W-R",
+ "-WX-",
+ "-WXR",
+ "U---",
+ "U--R",
+ "U-X-",
+ "U-XR",
+ "UW--",
+ "UW-R",
+ "UWX-",
+ "UWXR"
+};
+#define ITLB_BASE 0x00000000
+#define DTLB_BASE 0x00800000
+#define MAX_TLBs 64
+/* PTE High */
+#define GET_VALID(pte) ((pte) & 0x1)
+#define GET_SHARED(pte) ((pte) & 0x2)
+#define GET_ASID(pte) ((pte >> 2) & 0x0ff)
+#define GET_EPN(pte) ((pte) & 0xfffff000)
+
+/* PTE Low */
+#define GET_CBEHAVIOR(pte) ((pte) & 0x3)
+#define GET_PAGE_SIZE(pte) szTab[((pte >> 3) & 0x3)]
+#define GET_PROTECTION(pte) protTab[((pte >> 6) & 0xf)]
+#define GET_PPN(pte) ((pte) & 0xfffff000)
+
+#define PAGE_1K_MASK 0x00000000
+#define PAGE_4K_MASK 0x00000010
+#define PAGE_64K_MASK 0x00000080
+#define MMU_PAGESIZE_MASK (PAGE_64K_MASK | PAGE_4K_MASK)
+#define PAGE_1MB_MASK MMU_PAGESIZE_MASK
+#define PAGE_1K (1024)
+#define PAGE_4K (1024 * 4)
+#define PAGE_64K (1024 * 64)
+#define PAGE_1MB (1024 * 1024)
+
+#define HOW_TO_READ_TLB_CONTENT \
+ "[ ID] PPN EPN ASID Share CB P.Size PROT.\n"
+
+void print_single_tlb(unsigned long tlb, int single_print)
+{
+ regType_t pteH;
+ regType_t pteL;
+ unsigned int valid, shared, asid, epn, cb, ppn;
+ char *pSize;
+ char *pProt;
+
+ /*
+ ** in case of single print <single_print> is true, this implies:
+ ** 1) print the TLB in any case also if NOT VALID
+ ** 2) print out the header
+ */
+
+ pteH = getConfigReg(tlb);
+ valid = GET_VALID(pteH);
+ if (single_print)
+ printk(HOW_TO_READ_TLB_CONTENT);
+ else if (!valid)
+ return;
+
+ pteL = getConfigReg(tlb + 1);
+
+ shared = GET_SHARED(pteH);
+ asid = GET_ASID(pteH);
+ epn = GET_EPN(pteH);
+ cb = GET_CBEHAVIOR(pteL);
+ pSize = GET_PAGE_SIZE(pteL);
+ pProt = GET_PROTECTION(pteL);
+ ppn = GET_PPN(pteL);
+ printk("[%c%2ld] 0x%08x 0x%08x %03d %02x %02x %4s %s\n",
+ ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP),
+ ppn, epn, asid, shared, cb, pSize, pProt);
+}
+
+void print_dtlb(void)
+{
+ int count;
+ unsigned long tlb;
+
+ printk(" ================= SH-5 D-TLBs Status ===================\n");
+ printk(HOW_TO_READ_TLB_CONTENT);
+ tlb = DTLB_BASE;
+ for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
+ print_single_tlb(tlb, 0);
+ printk
+ (" =============================================================\n");
+}
+
+void print_itlb(void)
+{
+ int count;
+ unsigned long tlb;
+
+ printk(" ================= SH-5 I-TLBs Status ===================\n");
+ printk(HOW_TO_READ_TLB_CONTENT);
+ tlb = ITLB_BASE;
+ for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
+ print_single_tlb(tlb, 0);
+ printk
+ (" =============================================================\n");
+}
+
+/* ======================================================================= */
+
+#ifdef CONFIG_POOR_MANS_STRACE
+
+#include "syscalltab.h"
+
+struct ring_node {
+ int evt;
+ int ret_addr;
+ int event;
+ int tra;
+ int pid;
+ unsigned long sp;
+ unsigned long pc;
+};
+
+static struct ring_node event_ring[16];
+static int event_ptr = 0;
+
+struct stored_syscall_data {
+ int pid;
+ int syscall_number;
+};
+
+#define N_STORED_SYSCALLS 16
+
+static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS];
+static int syscall_next=0;
+static int syscall_next_print=0;
+
+void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs)
+{
+ int syscallno = tra & 0xff;
+ unsigned long sp;
+ unsigned long stack_bottom;
+ int pid;
+ struct ring_node *rr;
+
+ pid = current->pid;
+ stack_bottom = (unsigned long) task_stack_page(current);
+ asm volatile("ori r15, 0, %0" : "=r" (sp));
+ rr = event_ring + event_ptr;
+ rr->evt = evt;
+ rr->ret_addr = ret_addr;
+ rr->event = event;
+ rr->tra = tra;
+ rr->pid = pid;
+ rr->sp = sp;
+ rr->pc = regs->pc;
+
+ if (sp < stack_bottom + 3092) {
+ printk("evt_debug : stack underflow report\n");
+ int i, j;
+ for (j=0, i = event_ptr; j<16; j++) {
+ rr = event_ring + i;
+ printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n",
+ rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc);
+ i--;
+ i &= 15;
+ }
+ panic("STACK UNDERFLOW\n");
+ }
+
+ event_ptr = (event_ptr + 1) & 15;
+
+ if ((event == 2) && (evt == 0x160)) {
+ if (syscallno < NUM_SYSCALL_INFO_ENTRIES) {
+ /* Store the syscall information to print later. We
+ * can't print this now - currently we're running with
+ * SR.BL=1, so we can't take a tlbmiss (which could occur
+ * in the console drivers under printk).
+ *
+ * Just overwrite old entries on ring overflow - this
+ * is only for last-hope debugging. */
+ stored_syscalls[syscall_next].pid = current->pid;
+ stored_syscalls[syscall_next].syscall_number = syscallno;
+ syscall_next++;
+ syscall_next &= (N_STORED_SYSCALLS - 1);
+ }
+ }
+}
+
+static void drain_syscalls(void) {
+ while (syscall_next_print != syscall_next) {
+ printk("Task %d: %s()\n",
+ stored_syscalls[syscall_next_print].pid,
+ syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name);
+ syscall_next_print++;
+ syscall_next_print &= (N_STORED_SYSCALLS - 1);
+ }
+}
+
+void evt_debug2(unsigned int ret)
+{
+ drain_syscalls();
+ printk("Task %d: syscall returns %08x\n", current->pid, ret);
+}
+
+void evt_debug_ret_from_irq(struct pt_regs *regs)
+{
+ int pid;
+ struct ring_node *rr;
+
+ pid = current->pid;
+ rr = event_ring + event_ptr;
+ rr->evt = 0xffff;
+ rr->ret_addr = 0;
+ rr->event = 0;
+ rr->tra = 0;
+ rr->pid = pid;
+ rr->pc = regs->pc;
+ event_ptr = (event_ptr + 1) & 15;
+}
+
+void evt_debug_ret_from_exc(struct pt_regs *regs)
+{
+ int pid;
+ struct ring_node *rr;
+
+ pid = current->pid;
+ rr = event_ring + event_ptr;
+ rr->evt = 0xfffe;
+ rr->ret_addr = 0;
+ rr->event = 0;
+ rr->tra = 0;
+ rr->pid = pid;
+ rr->pc = regs->pc;
+ event_ptr = (event_ptr + 1) & 15;
+}
+
+#endif /* CONFIG_POOR_MANS_STRACE */
+
+/* ======================================================================= */
+
+void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
+{
+
+ unsigned long long ah, al, bh, bl, ch, cl;
+
+ printk("\n");
+ printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n",
+ ((from) ? from : "???"), current->pid, trapnr, signr);
+
+ asm volatile ("getcon " __EXPEVT ", %0":"=r"(ah));
+ asm volatile ("getcon " __EXPEVT ", %0":"=r"(al));
+ ah = (ah) >> 32;
+ al = (al) & 0xffffffff;
+ asm volatile ("getcon " __KCR1 ", %0":"=r"(bh));
+ asm volatile ("getcon " __KCR1 ", %0":"=r"(bl));
+ bh = (bh) >> 32;
+ bl = (bl) & 0xffffffff;
+ asm volatile ("getcon " __INTEVT ", %0":"=r"(ch));
+ asm volatile ("getcon " __INTEVT ", %0":"=r"(cl));
+ ch = (ch) >> 32;
+ cl = (cl) & 0xffffffff;
+ printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ asm volatile ("getcon " __PEXPEVT ", %0":"=r"(ah));
+ asm volatile ("getcon " __PEXPEVT ", %0":"=r"(al));
+ ah = (ah) >> 32;
+ al = (al) & 0xffffffff;
+ asm volatile ("getcon " __PSPC ", %0":"=r"(bh));
+ asm volatile ("getcon " __PSPC ", %0":"=r"(bl));
+ bh = (bh) >> 32;
+ bl = (bl) & 0xffffffff;
+ asm volatile ("getcon " __PSSR ", %0":"=r"(ch));
+ asm volatile ("getcon " __PSSR ", %0":"=r"(cl));
+ ch = (ch) >> 32;
+ cl = (cl) & 0xffffffff;
+ printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->pc) >> 32;
+ al = (regs->pc) & 0xffffffff;
+ bh = (regs->regs[18]) >> 32;
+ bl = (regs->regs[18]) & 0xffffffff;
+ ch = (regs->regs[15]) >> 32;
+ cl = (regs->regs[15]) & 0xffffffff;
+ printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->sr) >> 32;
+ al = (regs->sr) & 0xffffffff;
+ asm volatile ("getcon " __TEA ", %0":"=r"(bh));
+ asm volatile ("getcon " __TEA ", %0":"=r"(bl));
+ bh = (bh) >> 32;
+ bl = (bl) & 0xffffffff;
+ asm volatile ("getcon " __KCR0 ", %0":"=r"(ch));
+ asm volatile ("getcon " __KCR0 ", %0":"=r"(cl));
+ ch = (ch) >> 32;
+ cl = (cl) & 0xffffffff;
+ printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[0]) >> 32;
+ al = (regs->regs[0]) & 0xffffffff;
+ bh = (regs->regs[1]) >> 32;
+ bl = (regs->regs[1]) & 0xffffffff;
+ ch = (regs->regs[2]) >> 32;
+ cl = (regs->regs[2]) & 0xffffffff;
+ printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[3]) >> 32;
+ al = (regs->regs[3]) & 0xffffffff;
+ bh = (regs->regs[4]) >> 32;
+ bl = (regs->regs[4]) & 0xffffffff;
+ ch = (regs->regs[5]) >> 32;
+ cl = (regs->regs[5]) & 0xffffffff;
+ printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[6]) >> 32;
+ al = (regs->regs[6]) & 0xffffffff;
+ bh = (regs->regs[7]) >> 32;
+ bl = (regs->regs[7]) & 0xffffffff;
+ ch = (regs->regs[8]) >> 32;
+ cl = (regs->regs[8]) & 0xffffffff;
+ printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[9]) >> 32;
+ al = (regs->regs[9]) & 0xffffffff;
+ bh = (regs->regs[10]) >> 32;
+ bl = (regs->regs[10]) & 0xffffffff;
+ ch = (regs->regs[11]) >> 32;
+ cl = (regs->regs[11]) & 0xffffffff;
+ printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+ printk("....\n");
+
+ ah = (regs->tregs[0]) >> 32;
+ al = (regs->tregs[0]) & 0xffffffff;
+ bh = (regs->tregs[1]) >> 32;
+ bl = (regs->tregs[1]) & 0xffffffff;
+ ch = (regs->tregs[2]) >> 32;
+ cl = (regs->tregs[2]) & 0xffffffff;
+ printk("T0 : %08Lx%08Lx T1 : %08Lx%08Lx T2 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+ printk("....\n");
+
+ print_dtlb();
+ print_itlb();
+}
+
+/* ======================================================================= */
+
+/*
+** Depending on <base> scan the MMU, Data or Instruction side
+** looking for a valid mapping matching Eaddr & asid.
+** Return -1 if not found or the TLB id entry otherwise.
+** Note: it works only for 4k pages!
+*/
+static unsigned long
+lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid)
+{
+ regType_t pteH;
+ unsigned long epn;
+ int count;
+
+ epn = Eaddr & 0xfffff000;
+
+ for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) {
+ pteH = getConfigReg(base);
+ if (GET_VALID(pteH))
+ if ((unsigned long) GET_EPN(pteH) == epn)
+ if ((unsigned long) GET_ASID(pteH) == asid)
+ break;
+ }
+ return ((unsigned long) ((count < MAX_TLBs) ? base : -1));
+}
+
+unsigned long lookup_dtlb(unsigned long Eaddr)
+{
+ unsigned long asid = get_asid();
+ return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid));
+}
+
+unsigned long lookup_itlb(unsigned long Eaddr)
+{
+ unsigned long asid = get_asid();
+ return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid));
+}
+
+void print_page(struct page *page)
+{
+ printk(" page[%p] -> index 0x%lx, count 0x%x, flags 0x%lx\n",
+ page, page->index, page_count(page), page->flags);
+ printk(" address_space = %p, pages =%ld\n", page->mapping,
+ page->mapping->nrpages);
+
+}
diff --git a/arch/sh/lib64/memcpy.c b/arch/sh/lib64/memcpy.c
new file mode 100644
index 000000000000..fba436a92bfa
--- /dev/null
+++ b/arch/sh/lib64/memcpy.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 Mark Debbage (Mark.Debbage@superh.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/string.h>
+
+// This is a simplistic optimization of memcpy to increase the
+// granularity of access beyond one byte using aligned
+// loads and stores. This is not an optimal implementation
+// for SH-5 (especially with regard to prefetching and the cache),
+// and a better version should be provided later ...
+
+void *memcpy(void *dest, const void *src, size_t count)
+{
+ char *d = (char *) dest, *s = (char *) src;
+
+ if (count >= 32) {
+ int i = 8 - (((unsigned long) d) & 0x7);
+
+ if (i != 8)
+ while (i-- && count--) {
+ *d++ = *s++;
+ }
+
+ if (((((unsigned long) d) & 0x7) == 0) &&
+ ((((unsigned long) s) & 0x7) == 0)) {
+ while (count >= 32) {
+ unsigned long long t1, t2, t3, t4;
+ t1 = *(unsigned long long *) (s);
+ t2 = *(unsigned long long *) (s + 8);
+ t3 = *(unsigned long long *) (s + 16);
+ t4 = *(unsigned long long *) (s + 24);
+ *(unsigned long long *) (d) = t1;
+ *(unsigned long long *) (d + 8) = t2;
+ *(unsigned long long *) (d + 16) = t3;
+ *(unsigned long long *) (d + 24) = t4;
+ d += 32;
+ s += 32;
+ count -= 32;
+ }
+ while (count >= 8) {
+ *(unsigned long long *) d =
+ *(unsigned long long *) s;
+ d += 8;
+ s += 8;
+ count -= 8;
+ }
+ }
+
+ if (((((unsigned long) d) & 0x3) == 0) &&
+ ((((unsigned long) s) & 0x3) == 0)) {
+ while (count >= 4) {
+ *(unsigned long *) d = *(unsigned long *) s;
+ d += 4;
+ s += 4;
+ count -= 4;
+ }
+ }
+
+ if (((((unsigned long) d) & 0x1) == 0) &&
+ ((((unsigned long) s) & 0x1) == 0)) {
+ while (count >= 2) {
+ *(unsigned short *) d = *(unsigned short *) s;
+ d += 2;
+ s += 2;
+ count -= 2;
+ }
+ }
+ }
+
+ while (count--) {
+ *d++ = *s++;
+ }
+
+ return d;
+}
diff --git a/arch/sh/lib64/panic.c b/arch/sh/lib64/panic.c
new file mode 100644
index 000000000000..ff559e2a96f7
--- /dev/null
+++ b/arch/sh/lib64/panic.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2003 Richard Curnow, SuperH UK Limited
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/cpu/registers.h>
+
+/* THIS IS A PHYSICAL ADDRESS */
+#define HDSP2534_ADDR (0x04002100)
+
+#ifdef CONFIG_SH_CAYMAN
+
+static void poor_mans_delay(void)
+{
+ int i;
+ for (i = 0; i < 2500000; i++) {
+ } /* poor man's delay */
+}
+
+static void show_value(unsigned long x)
+{
+ int i;
+ unsigned nibble;
+ for (i = 0; i < 8; i++) {
+ nibble = ((x >> (i * 4)) & 0xf);
+
+ ctrl_outb(nibble + ((nibble > 9) ? 55 : 48),
+ HDSP2534_ADDR + 0xe0 + ((7 - i) << 2));
+ }
+}
+
+#endif
+
+void
+panic_handler(unsigned long panicPC, unsigned long panicSSR,
+ unsigned long panicEXPEVT)
+{
+#ifdef CONFIG_SH_CAYMAN
+ while (1) {
+ /* This piece of code displays the PC on the LED display */
+ show_value(panicPC);
+ poor_mans_delay();
+ show_value(panicSSR);
+ poor_mans_delay();
+ show_value(panicEXPEVT);
+ poor_mans_delay();
+ }
+#endif
+
+ /* Never return from the panic handler */
+ for (;;) ;
+
+}
diff --git a/arch/sh/lib64/udelay.c b/arch/sh/lib64/udelay.c
new file mode 100644
index 000000000000..23c7d17fb9f7
--- /dev/null
+++ b/arch/sh/lib64/udelay.c
@@ -0,0 +1,56 @@
+/*
+ * arch/sh/lib64/udelay.c
+ *
+ * Delay routines, using a pre-computed "loops_per_jiffy" value.
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003, 2004 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sched.h>
+#include <asm/param.h>
+
+/*
+ * Use only for very small delays (< 1 msec).
+ *
+ * The active part of our cycle counter is only 32-bits wide, and
+ * we're treating the difference between two marks as signed. On
+ * a 1GHz box, that's about 2 seconds.
+ */
+
+void __delay(int loops)
+{
+ long long dummy;
+ __asm__ __volatile__("gettr tr0, %1\n\t"
+ "pta $+4, tr0\n\t"
+ "addi %0, -1, %0\n\t"
+ "bne %0, r63, tr0\n\t"
+ "ptabs %1, tr0\n\t":"=r"(loops),
+ "=r"(dummy)
+ :"0"(loops));
+}
+
+void __udelay(unsigned long long usecs, unsigned long lpj)
+{
+ usecs *= (((unsigned long long) HZ << 32) / 1000000) * lpj;
+ __delay((long long) usecs >> 32);
+}
+
+void __ndelay(unsigned long long nsecs, unsigned long lpj)
+{
+ nsecs *= (((unsigned long long) HZ << 32) / 1000000000) * lpj;
+ __delay((long long) nsecs >> 32);
+}
+
+void udelay(unsigned long usecs)
+{
+ __udelay(usecs, cpu_data[raw_smp_processor_id()].loops_per_jiffy);
+}
+
+void ndelay(unsigned long nsecs)
+{
+ __ndelay(nsecs, cpu_data[raw_smp_processor_id()].loops_per_jiffy);
+}
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 1265f204f7d1..f549b8cd2501 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -1,193 +1,3 @@
-#
-# Processor families
-#
-config CPU_SH2
- bool
-
-config CPU_SH2A
- bool
- select CPU_SH2
-
-config CPU_SH3
- bool
- select CPU_HAS_INTEVT
- select CPU_HAS_SR_RB
-
-config CPU_SH4
- bool
- select CPU_HAS_INTEVT
- select CPU_HAS_SR_RB
- select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
- select CPU_HAS_FPU if !CPU_SH4AL_DSP
-
-config CPU_SH4A
- bool
- select CPU_SH4
-
-config CPU_SH4AL_DSP
- bool
- select CPU_SH4A
- select CPU_HAS_DSP
-
-config CPU_SHX2
- bool
-
-config CPU_SHX3
- bool
-
-choice
- prompt "Processor sub-type selection"
-
-#
-# Processor subtypes
-#
-
-# SH-2 Processor Support
-
-config CPU_SUBTYPE_SH7619
- bool "Support SH7619 processor"
- select CPU_SH2
-
-# SH-2A Processor Support
-
-config CPU_SUBTYPE_SH7206
- bool "Support SH7206 processor"
- select CPU_SH2A
-
-# SH-3 Processor Support
-
-config CPU_SUBTYPE_SH7705
- bool "Support SH7705 processor"
- select CPU_SH3
-
-config CPU_SUBTYPE_SH7706
- bool "Support SH7706 processor"
- select CPU_SH3
- help
- Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
-
-config CPU_SUBTYPE_SH7707
- bool "Support SH7707 processor"
- select CPU_SH3
- help
- Select SH7707 if you have a 60 Mhz SH-3 HD6417707 CPU.
-
-config CPU_SUBTYPE_SH7708
- bool "Support SH7708 processor"
- select CPU_SH3
- help
- Select SH7708 if you have a 60 Mhz SH-3 HD6417708S or
- if you have a 100 Mhz SH-3 HD6417708R CPU.
-
-config CPU_SUBTYPE_SH7709
- bool "Support SH7709 processor"
- select CPU_SH3
- help
- Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
-
-config CPU_SUBTYPE_SH7710
- bool "Support SH7710 processor"
- select CPU_SH3
- select CPU_HAS_DSP
- help
- Select SH7710 if you have a SH3-DSP SH7710 CPU.
-
-config CPU_SUBTYPE_SH7712
- bool "Support SH7712 processor"
- select CPU_SH3
- select CPU_HAS_DSP
- help
- Select SH7712 if you have a SH3-DSP SH7712 CPU.
-
-config CPU_SUBTYPE_SH7720
- bool "Support SH7720 processor"
- select CPU_SH3
- select CPU_HAS_DSP
- help
- Select SH7720 if you have a SH3-DSP SH7720 CPU.
-
-# SH-4 Processor Support
-
-config CPU_SUBTYPE_SH7750
- bool "Support SH7750 processor"
- select CPU_SH4
- help
- Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
-
-config CPU_SUBTYPE_SH7091
- bool "Support SH7091 processor"
- select CPU_SH4
- help
- Select SH7091 if you have an SH-4 based Sega device (such as
- the Dreamcast, Naomi, and Naomi 2).
-
-config CPU_SUBTYPE_SH7750R
- bool "Support SH7750R processor"
- select CPU_SH4
-
-config CPU_SUBTYPE_SH7750S
- bool "Support SH7750S processor"
- select CPU_SH4
-
-config CPU_SUBTYPE_SH7751
- bool "Support SH7751 processor"
- select CPU_SH4
- help
- Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
- or if you have a HD6417751R CPU.
-
-config CPU_SUBTYPE_SH7751R
- bool "Support SH7751R processor"
- select CPU_SH4
-
-config CPU_SUBTYPE_SH7760
- bool "Support SH7760 processor"
- select CPU_SH4
-
-config CPU_SUBTYPE_SH4_202
- bool "Support SH4-202 processor"
- select CPU_SH4
-
-# SH-4A Processor Support
-
-config CPU_SUBTYPE_SH7770
- bool "Support SH7770 processor"
- select CPU_SH4A
-
-config CPU_SUBTYPE_SH7780
- bool "Support SH7780 processor"
- select CPU_SH4A
-
-config CPU_SUBTYPE_SH7785
- bool "Support SH7785 processor"
- select CPU_SH4A
- select CPU_SHX2
- select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_NUMA
-
-config CPU_SUBTYPE_SHX3
- bool "Support SH-X3 processor"
- select CPU_SH4A
- select CPU_SHX3
- select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_NUMA
- select SYS_SUPPORTS_SMP
-
-# SH4AL-DSP Processor Support
-
-config CPU_SUBTYPE_SH7343
- bool "Support SH7343 processor"
- select CPU_SH4AL_DSP
-
-config CPU_SUBTYPE_SH7722
- bool "Support SH7722 processor"
- select CPU_SH4AL_DSP
- select CPU_SHX2
- select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_NUMA
-
-endchoice
-
menu "Memory management options"
config QUICKLIST
@@ -207,7 +17,8 @@ config MMU
config PAGE_OFFSET
hex
- default "0x80000000" if MMU
+ default "0x80000000" if MMU && SUPERH32
+ default "0x20000000" if MMU && SUPERH64
default "0x00000000"
config MEMORY_START
@@ -228,17 +39,28 @@ config MEMORY_START
config MEMORY_SIZE
hex "Physical memory size"
- default "0x00400000"
+ default "0x04000000"
help
This sets the default memory size assumed by your SH kernel. It can
be overridden as normal by the 'mem=' argument on the kernel command
line. If unsure, consult your board specifications or just leave it
- as 0x00400000 which was the default value before this became
+ as 0x04000000 which was the default value before this became
configurable.
+# Physical addressing modes
+
+config 29BIT
+ def_bool !32BIT
+ depends on SUPERH32
+
config 32BIT
+ bool
+ default y if CPU_SH5
+
+config PMB
bool "Support 32-bit physical addressing through PMB"
depends on MMU && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
+ select 32BIT
default y
help
If you say Y here, physical addressing will be extended to
@@ -256,7 +78,7 @@ config X2TLB
config VSYSCALL
bool "Support vsyscall page"
- depends on MMU
+ depends on MMU && (CPU_SH3 || CPU_SH4)
default y
help
This will enable support for the kernel mapping a vDSO page
@@ -335,7 +157,7 @@ config PAGE_SIZE_8KB
config PAGE_SIZE_64KB
bool "64kB"
- depends on CPU_SH4
+ depends on CPU_SH4 || CPU_SH5
help
This enables support for 64kB pages, possible on all SH-4
CPUs and later.
@@ -344,7 +166,7 @@ endchoice
choice
prompt "HugeTLB page size"
- depends on HUGETLB_PAGE && CPU_SH4 && MMU
+ depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU
default HUGETLB_PAGE_SIZE_64K
config HUGETLB_PAGE_SIZE_64K
@@ -365,6 +187,10 @@ config HUGETLB_PAGE_SIZE_64MB
bool "64MB"
depends on X2TLB
+config HUGETLB_PAGE_SIZE_512MB
+ bool "512MB"
+ depends on CPU_SH5
+
endchoice
source "mm/Kconfig"
@@ -392,12 +218,12 @@ config SH_DIRECT_MAPPED
choice
prompt "Cache mode"
- default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4
+ default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5
default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A)
config CACHE_WRITEBACK
bool "Write-back"
- depends on CPU_SH2A || CPU_SH3 || CPU_SH4
+ depends on CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5
config CACHE_WRITETHROUGH
bool "Write-through"
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index aa44607f072d..9f4bc3d90b1e 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -1,37 +1,5 @@
-#
-# Makefile for the Linux SuperH-specific parts of the memory manager.
-#
-
-obj-y := init.o extable.o consistent.o
-
-ifndef CONFIG_CACHE_OFF
-obj-$(CONFIG_CPU_SH2) += cache-sh2.o
-obj-$(CONFIG_CPU_SH3) += cache-sh3.o
-obj-$(CONFIG_CPU_SH4) += cache-sh4.o
-obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
+ifeq ($(CONFIG_SUPERH32),y)
+include ${srctree}/arch/sh/mm/Makefile_32
+else
+include ${srctree}/arch/sh/mm/Makefile_64
endif
-
-mmu-y := tlb-nommu.o pg-nommu.o
-mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
- ioremap.o
-
-obj-y += $(mmu-y)
-
-ifdef CONFIG_DEBUG_FS
-obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
-endif
-
-ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4) += tlb-sh4.o
-ifndef CONFIG_CACHE_OFF
-obj-$(CONFIG_CPU_SH4) += pg-sh4.o
-obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
-endif
-endif
-
-obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_32BIT) += pmb.o
-obj-$(CONFIG_NUMA) += numa.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32
new file mode 100644
index 000000000000..e295db60b91b
--- /dev/null
+++ b/arch/sh/mm/Makefile_32
@@ -0,0 +1,36 @@
+#
+# Makefile for the Linux SuperH-specific parts of the memory manager.
+#
+
+obj-y := init.o extable_32.o consistent.o
+
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH2) += cache-sh2.o
+obj-$(CONFIG_CPU_SH3) += cache-sh3.o
+obj-$(CONFIG_CPU_SH4) += cache-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
+endif
+
+mmu-y := tlb-nommu.o pg-nommu.o
+mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o
+
+obj-y += $(mmu-y)
+
+ifdef CONFIG_DEBUG_FS
+obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
+endif
+
+ifdef CONFIG_MMU
+obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
+obj-$(CONFIG_CPU_SH4) += tlb-sh4.o
+ifndef CONFIG_CACHE_OFF
+obj-$(CONFIG_CPU_SH4) += pg-sh4.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
+endif
+endif
+
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_PMB) += pmb.o
+obj-$(CONFIG_NUMA) += numa.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64
new file mode 100644
index 000000000000..cbd6aa33c5ac
--- /dev/null
+++ b/arch/sh/mm/Makefile_64
@@ -0,0 +1,44 @@
+#
+# Makefile for the Linux SuperH-specific parts of the memory manager.
+#
+
+obj-y := init.o extable_64.o consistent.o
+
+mmu-y := tlb-nommu.o pg-nommu.o
+mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o
+
+ifndef CONFIG_CACHE_OFF
+obj-y += cache-sh5.o
+endif
+
+obj-y += $(mmu-y)
+
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_NUMA) += numa.o
+
+EXTRA_CFLAGS += -Werror
+
+# Special flags for fault_64.o. This puts restrictions on the number of
+# caller-save registers that the compiler can target when building this file.
+# This is required because the code is called from a context in entry.S where
+# very few registers have been saved in the exception handler (for speed
+# reasons).
+# The caller save registers that have been saved and which can be used are
+# r2,r3,r4,r5 : argument passing
+# r15, r18 : SP and LINK
+# tr0-4 : allow all caller-save TR's. The compiler seems to be able to make
+# use of them, so it's probably beneficial to performance to save them
+# and have them available for it.
+#
+# The resources not listed below are callee save, i.e. the compiler is free to
+# use any of them and will spill them to the stack itself.
+
+CFLAGS_fault_64.o += -ffixed-r7 \
+ -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
+ -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
+ -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
+ -ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \
+ -ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \
+ -ffixed-r41 -ffixed-r42 -ffixed-r43 \
+ -ffixed-r60 -ffixed-r61 -ffixed-r62 \
+ -fomit-frame-pointer
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index de6d2c9aa477..db6d950b6f5e 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -22,7 +22,8 @@ enum cache_type {
CACHE_TYPE_UNIFIED,
};
-static int cache_seq_show(struct seq_file *file, void *iter)
+static int __uses_jump_to_uncached cache_seq_show(struct seq_file *file,
+ void *iter)
{
unsigned int cache_type = (unsigned int)file->private;
struct cache_info *cache;
@@ -34,11 +35,11 @@ static int cache_seq_show(struct seq_file *file, void *iter)
* Go uncached immediately so we don't skew the results any
* more than we already are..
*/
- jump_to_P2();
+ jump_to_uncached();
ccr = ctrl_inl(CCR);
if ((ccr & CCR_CACHE_ENABLE) == 0) {
- back_to_P1();
+ back_to_cached();
seq_printf(file, "disabled\n");
return 0;
@@ -104,7 +105,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
addrstart += cache->way_incr;
}
- back_to_P1();
+ back_to_cached();
return 0;
}
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 226b190c5b9c..43d7ff6b6ec7 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -190,7 +190,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
* .. which happens to be the same behavior as flush_icache_range().
* So, we simply flush out a line.
*/
-void flush_cache_sigtramp(unsigned long addr)
+void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr)
{
unsigned long v, index;
unsigned long flags;
@@ -205,13 +205,13 @@ void flush_cache_sigtramp(unsigned long addr)
(v & boot_cpu_data.icache.entry_mask);
local_irq_save(flags);
- jump_to_P2();
+ jump_to_uncached();
for (i = 0; i < boot_cpu_data.icache.ways;
i++, index += boot_cpu_data.icache.way_incr)
ctrl_outl(0, index); /* Clear out Valid-bit */
- back_to_P1();
+ back_to_cached();
wmb();
local_irq_restore(flags);
}
@@ -256,12 +256,12 @@ void flush_dcache_page(struct page *page)
}
/* TODO: Selective icache invalidation through IC address array.. */
-static inline void flush_icache_all(void)
+static inline void __uses_jump_to_uncached flush_icache_all(void)
{
unsigned long flags, ccr;
local_irq_save(flags);
- jump_to_P2();
+ jump_to_uncached();
/* Flush I-cache */
ccr = ctrl_inl(CCR);
@@ -269,11 +269,11 @@ static inline void flush_icache_all(void)
ctrl_outl(ccr, CCR);
/*
- * back_to_P1() will take care of the barrier for us, don't add
+ * back_to_cached() will take care of the barrier for us, don't add
* another one!
*/
- back_to_P1();
+ back_to_cached();
local_irq_restore(flags);
}
diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c
new file mode 100644
index 000000000000..4617e3aeee73
--- /dev/null
+++ b/arch/sh/mm/cache-sh5.c
@@ -0,0 +1,1029 @@
+/*
+ * arch/sh/mm/cache-sh5.c
+ *
+ * Original version Copyright (C) 2000, 2001 Paolo Alberelli
+ * Second version Copyright (C) benedict.gaster@superh.com 2002
+ * Third version Copyright Richard.Curnow@superh.com 2003
+ * Hacks to third version Copyright (C) 2003 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/tlb.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/pgalloc.h> /* for flush_itlb_range */
+
+#include <linux/proc_fs.h>
+
+/* This function is in entry.S */
+extern unsigned long switch_and_save_asid(unsigned long new_asid);
+
+/* Wired TLB entry for the D-cache */
+static unsigned long long dtlb_cache_slot;
+
+/**
+ * sh64_cache_init()
+ *
+ * This is pretty much just a straightforward clone of the SH
+ * detect_cpu_and_cache_system().
+ *
+ * This function is responsible for setting up all of the cache
+ * info dynamically as well as taking care of CPU probing and
+ * setting up the relevant subtype data.
+ *
+ * FIXME: For the time being, we only really support the SH5-101
+ * out of the box, and don't support dynamic probing for things
+ * like the SH5-103 or even cut2 of the SH5-101. Implement this
+ * later!
+ */
+int __init sh64_cache_init(void)
+{
+ /*
+ * First, setup some sane values for the I-cache.
+ */
+ cpu_data->icache.ways = 4;
+ cpu_data->icache.sets = 256;
+ cpu_data->icache.linesz = L1_CACHE_BYTES;
+
+ /*
+ * FIXME: This can probably be cleaned up a bit as well.. for example,
+ * do we really need the way shift _and_ the way_step_shift ?? Judging
+ * by the existing code, I would guess no.. is there any valid reason
+ * why we need to be tracking this around?
+ */
+ cpu_data->icache.way_shift = 13;
+ cpu_data->icache.entry_shift = 5;
+ cpu_data->icache.set_shift = 4;
+ cpu_data->icache.way_step_shift = 16;
+ cpu_data->icache.asid_shift = 2;
+
+ /*
+ * way offset = cache size / associativity, so just don't factor in
+ * associativity in the first place..
+ */
+ cpu_data->icache.way_ofs = cpu_data->icache.sets *
+ cpu_data->icache.linesz;
+
+ cpu_data->icache.asid_mask = 0x3fc;
+ cpu_data->icache.idx_mask = 0x1fe0;
+ cpu_data->icache.epn_mask = 0xffffe000;
+ cpu_data->icache.flags = 0;
+
+ /*
+ * Next, setup some sane values for the D-cache.
+ *
+ * On the SH5, these are pretty consistent with the I-cache settings,
+ * so we just copy over the existing definitions.. these can be fixed
+ * up later, especially if we add runtime CPU probing.
+ *
+ * Though in the meantime it saves us from having to duplicate all of
+ * the above definitions..
+ */
+ cpu_data->dcache = cpu_data->icache;
+
+ /*
+ * Setup any cache-related flags here
+ */
+#if defined(CONFIG_DCACHE_WRITE_THROUGH)
+ set_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags));
+#elif defined(CONFIG_DCACHE_WRITE_BACK)
+ set_bit(SH_CACHE_MODE_WB, &(cpu_data->dcache.flags));
+#endif
+
+ /*
+ * We also need to reserve a slot for the D-cache in the DTLB, so we
+ * do this now ..
+ */
+ dtlb_cache_slot = sh64_get_wired_dtlb_entry();
+
+ return 0;
+}
+
+#ifdef CONFIG_DCACHE_DISABLED
+#define sh64_dcache_purge_all() do { } while (0)
+#define sh64_dcache_purge_coloured_phy_page(paddr, eaddr) do { } while (0)
+#define sh64_dcache_purge_user_range(mm, start, end) do { } while (0)
+#define sh64_dcache_purge_phy_page(paddr) do { } while (0)
+#define sh64_dcache_purge_virt_page(mm, eaddr) do { } while (0)
+#define sh64_dcache_purge_kernel_range(start, end) do { } while (0)
+#define sh64_dcache_wback_current_user_range(start, end) do { } while (0)
+#endif
+
+/*##########################################################################*/
+
+/* From here onwards, a rewrite of the implementation,
+ by Richard.Curnow@superh.com.
+
+ The major changes in this compared to the old version are;
+ 1. use more selective purging through OCBP instead of using ALLOCO to purge
+ by natural replacement. This avoids purging out unrelated cache lines
+ that happen to be in the same set.
+ 2. exploit the APIs copy_user_page and clear_user_page better
+ 3. be more selective about I-cache purging, in particular use invalidate_all
+ more sparingly.
+
+ */
+
+/*##########################################################################
+ SUPPORT FUNCTIONS
+ ##########################################################################*/
+
+/****************************************************************************/
+/* The following group of functions deal with mapping and unmapping a temporary
+ page into the DTLB slot that have been set aside for our exclusive use. */
+/* In order to accomplish this, we use the generic interface for adding and
+ removing a wired slot entry as defined in arch/sh/mm/tlb-sh5.c */
+/****************************************************************************/
+
+static unsigned long slot_own_flags;
+
+static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr)
+{
+ local_irq_save(slot_own_flags);
+ sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr);
+}
+
+static inline void sh64_teardown_dtlb_cache_slot(void)
+{
+ sh64_teardown_tlb_slot(dtlb_cache_slot);
+ local_irq_restore(slot_own_flags);
+}
+
+/****************************************************************************/
+
+#ifndef CONFIG_ICACHE_DISABLED
+
+static void __inline__ sh64_icache_inv_all(void)
+{
+ unsigned long long addr, flag, data;
+ unsigned int flags;
+
+ addr=ICCR0;
+ flag=ICCR0_ICI;
+ data=0;
+
+ /* Make this a critical section for safety (probably not strictly necessary.) */
+ local_irq_save(flags);
+
+ /* Without %1 it gets unexplicably wrong */
+ asm volatile("getcfg %3, 0, %0\n\t"
+ "or %0, %2, %0\n\t"
+ "putcfg %3, 0, %0\n\t"
+ "synci"
+ : "=&r" (data)
+ : "0" (data), "r" (flag), "r" (addr));
+
+ local_irq_restore(flags);
+}
+
+static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end)
+{
+ /* Invalidate range of addresses [start,end] from the I-cache, where
+ * the addresses lie in the kernel superpage. */
+
+ unsigned long long ullend, addr, aligned_start;
+#if (NEFF == 32)
+ aligned_start = (unsigned long long)(signed long long)(signed long) start;
+#else
+#error "NEFF != 32"
+#endif
+ aligned_start &= L1_CACHE_ALIGN_MASK;
+ addr = aligned_start;
+#if (NEFF == 32)
+ ullend = (unsigned long long) (signed long long) (signed long) end;
+#else
+#error "NEFF != 32"
+#endif
+ while (addr <= ullend) {
+ asm __volatile__ ("icbi %0, 0" : : "r" (addr));
+ addr += L1_CACHE_BYTES;
+ }
+}
+
+static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long eaddr)
+{
+ /* If we get called, we know that vma->vm_flags contains VM_EXEC.
+ Also, eaddr is page-aligned. */
+
+ unsigned long long addr, end_addr;
+ unsigned long flags = 0;
+ unsigned long running_asid, vma_asid;
+ addr = eaddr;
+ end_addr = addr + PAGE_SIZE;
+
+ /* Check whether we can use the current ASID for the I-cache
+ invalidation. For example, if we're called via
+ access_process_vm->flush_cache_page->here, (e.g. when reading from
+ /proc), 'running_asid' will be that of the reader, not of the
+ victim.
+
+ Also, note the risk that we might get pre-empted between the ASID
+ compare and blocking IRQs, and before we regain control, the
+ pid->ASID mapping changes. However, the whole cache will get
+ invalidated when the mapping is renewed, so the worst that can
+ happen is that the loop below ends up invalidating somebody else's
+ cache entries.
+ */
+
+ running_asid = get_asid();
+ vma_asid = (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK);
+ if (running_asid != vma_asid) {
+ local_irq_save(flags);
+ switch_and_save_asid(vma_asid);
+ }
+ while (addr < end_addr) {
+ /* Worth unrolling a little */
+ asm __volatile__("icbi %0, 0" : : "r" (addr));
+ asm __volatile__("icbi %0, 32" : : "r" (addr));
+ asm __volatile__("icbi %0, 64" : : "r" (addr));
+ asm __volatile__("icbi %0, 96" : : "r" (addr));
+ addr += 128;
+ }
+ if (running_asid != vma_asid) {
+ switch_and_save_asid(running_asid);
+ local_irq_restore(flags);
+ }
+}
+
+/****************************************************************************/
+
+static void sh64_icache_inv_user_page_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ /* Used for invalidating big chunks of I-cache, i.e. assume the range
+ is whole pages. If 'start' or 'end' is not page aligned, the code
+ is conservative and invalidates to the ends of the enclosing pages.
+ This is functionally OK, just a performance loss. */
+
+ /* See the comments below in sh64_dcache_purge_user_range() regarding
+ the choice of algorithm. However, for the I-cache option (2) isn't
+ available because there are no physical tags so aliases can't be
+ resolved. The icbi instruction has to be used through the user
+ mapping. Because icbi is cheaper than ocbp on a cache hit, it
+ would be cheaper to use the selective code for a large range than is
+ possible with the D-cache. Just assume 64 for now as a working
+ figure.
+ */
+
+ int n_pages;
+
+ if (!mm) return;
+
+ n_pages = ((end - start) >> PAGE_SHIFT);
+ if (n_pages >= 64) {
+ sh64_icache_inv_all();
+ } else {
+ unsigned long aligned_start;
+ unsigned long eaddr;
+ unsigned long after_last_page_start;
+ unsigned long mm_asid, current_asid;
+ unsigned long long flags = 0ULL;
+
+ mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+ current_asid = get_asid();
+
+ if (mm_asid != current_asid) {
+ /* Switch ASID and run the invalidate loop under cli */
+ local_irq_save(flags);
+ switch_and_save_asid(mm_asid);
+ }
+
+ aligned_start = start & PAGE_MASK;
+ after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK);
+
+ while (aligned_start < after_last_page_start) {
+ struct vm_area_struct *vma;
+ unsigned long vma_end;
+ vma = find_vma(mm, aligned_start);
+ if (!vma || (aligned_start <= vma->vm_end)) {
+ /* Avoid getting stuck in an error condition */
+ aligned_start += PAGE_SIZE;
+ continue;
+ }
+ vma_end = vma->vm_end;
+ if (vma->vm_flags & VM_EXEC) {
+ /* Executable */
+ eaddr = aligned_start;
+ while (eaddr < vma_end) {
+ sh64_icache_inv_user_page(vma, eaddr);
+ eaddr += PAGE_SIZE;
+ }
+ }
+ aligned_start = vma->vm_end; /* Skip to start of next region */
+ }
+ if (mm_asid != current_asid) {
+ switch_and_save_asid(current_asid);
+ local_irq_restore(flags);
+ }
+ }
+}
+
+static void sh64_icache_inv_user_small_range(struct mm_struct *mm,
+ unsigned long start, int len)
+{
+
+ /* Invalidate a small range of user context I-cache, not necessarily
+ page (or even cache-line) aligned. */
+
+ unsigned long long eaddr = start;
+ unsigned long long eaddr_end = start + len;
+ unsigned long current_asid, mm_asid;
+ unsigned long long flags;
+ unsigned long long epage_start;
+
+ /* Since this is used inside ptrace, the ASID in the mm context
+ typically won't match current_asid. We'll have to switch ASID to do
+ this. For safety, and given that the range will be small, do all
+ this under cli.
+
+ Note, there is a hazard that the ASID in mm->context is no longer
+ actually associated with mm, i.e. if the mm->context has started a
+ new cycle since mm was last active. However, this is just a
+ performance issue: all that happens is that we invalidate lines
+ belonging to another mm, so the owning process has to refill them
+ when that mm goes live again. mm itself can't have any cache
+ entries because there will have been a flush_cache_all when the new
+ mm->context cycle started. */
+
+ /* Align to start of cache line. Otherwise, suppose len==8 and start
+ was at 32N+28 : the last 4 bytes wouldn't get invalidated. */
+ eaddr = start & L1_CACHE_ALIGN_MASK;
+ eaddr_end = start + len;
+
+ local_irq_save(flags);
+ mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+ current_asid = switch_and_save_asid(mm_asid);
+
+ epage_start = eaddr & PAGE_MASK;
+
+ while (eaddr < eaddr_end)
+ {
+ asm __volatile__("icbi %0, 0" : : "r" (eaddr));
+ eaddr += L1_CACHE_BYTES;
+ }
+ switch_and_save_asid(current_asid);
+ local_irq_restore(flags);
+}
+
+static void sh64_icache_inv_current_user_range(unsigned long start, unsigned long end)
+{
+ /* The icbi instruction never raises ITLBMISS. i.e. if there's not a
+ cache hit on the virtual tag the instruction ends there, without a
+ TLB lookup. */
+
+ unsigned long long aligned_start;
+ unsigned long long ull_end;
+ unsigned long long addr;
+
+ ull_end = end;
+
+ /* Just invalidate over the range using the natural addresses. TLB
+ miss handling will be OK (TBC). Since it's for the current process,
+ either we're already in the right ASID context, or the ASIDs have
+ been recycled since we were last active in which case we might just
+ invalidate another processes I-cache entries : no worries, just a
+ performance drop for him. */
+ aligned_start = start & L1_CACHE_ALIGN_MASK;
+ addr = aligned_start;
+ while (addr < ull_end) {
+ asm __volatile__ ("icbi %0, 0" : : "r" (addr));
+ asm __volatile__ ("nop");
+ asm __volatile__ ("nop");
+ addr += L1_CACHE_BYTES;
+ }
+}
+
+#endif /* !CONFIG_ICACHE_DISABLED */
+
+/****************************************************************************/
+
+#ifndef CONFIG_DCACHE_DISABLED
+
+/* Buffer used as the target of alloco instructions to purge data from cache
+ sets by natural eviction. -- RPC */
+#define DUMMY_ALLOCO_AREA_SIZE L1_CACHE_SIZE_BYTES + (1024 * 4)
+static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, };
+
+/****************************************************************************/
+
+static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
+{
+ /* Purge all ways in a particular block of sets, specified by the base
+ set number and number of sets. Can handle wrap-around, if that's
+ needed. */
+
+ int dummy_buffer_base_set;
+ unsigned long long eaddr, eaddr0, eaddr1;
+ int j;
+ int set_offset;
+
+ dummy_buffer_base_set = ((int)&dummy_alloco_area & cpu_data->dcache.idx_mask) >> cpu_data->dcache.entry_shift;
+ set_offset = sets_to_purge_base - dummy_buffer_base_set;
+
+ for (j=0; j<n_sets; j++, set_offset++) {
+ set_offset &= (cpu_data->dcache.sets - 1);
+ eaddr0 = (unsigned long long)dummy_alloco_area + (set_offset << cpu_data->dcache.entry_shift);
+
+ /* Do one alloco which hits the required set per cache way. For
+ write-back mode, this will purge the #ways resident lines. There's
+ little point unrolling this loop because the allocos stall more if
+ they're too close together. */
+ eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
+ for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
+ asm __volatile__ ("alloco %0, 0" : : "r" (eaddr));
+ asm __volatile__ ("synco"); /* TAKum03020 */
+ }
+
+ eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
+ for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
+ /* Load from each address. Required because alloco is a NOP if
+ the cache is write-through. Write-through is a config option. */
+ if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)))
+ *(volatile unsigned char *)(int)eaddr;
+ }
+ }
+
+ /* Don't use OCBI to invalidate the lines. That costs cycles directly.
+ If the dummy block is just left resident, it will naturally get
+ evicted as required. */
+
+ return;
+}
+
+/****************************************************************************/
+
+static void sh64_dcache_purge_all(void)
+{
+ /* Purge the entire contents of the dcache. The most efficient way to
+ achieve this is to use alloco instructions on a region of unused
+ memory equal in size to the cache, thereby causing the current
+ contents to be discarded by natural eviction. The alternative,
+ namely reading every tag, setting up a mapping for the corresponding
+ page and doing an OCBP for the line, would be much more expensive.
+ */
+
+ sh64_dcache_purge_sets(0, cpu_data->dcache.sets);
+
+ return;
+
+}
+
+/****************************************************************************/
+
+static void sh64_dcache_purge_kernel_range(unsigned long start, unsigned long end)
+{
+ /* Purge the range of addresses [start,end] from the D-cache. The
+ addresses lie in the superpage mapping. There's no harm if we
+ overpurge at either end - just a small performance loss. */
+ unsigned long long ullend, addr, aligned_start;
+#if (NEFF == 32)
+ aligned_start = (unsigned long long)(signed long long)(signed long) start;
+#else
+#error "NEFF != 32"
+#endif
+ aligned_start &= L1_CACHE_ALIGN_MASK;
+ addr = aligned_start;
+#if (NEFF == 32)
+ ullend = (unsigned long long) (signed long long) (signed long) end;
+#else
+#error "NEFF != 32"
+#endif
+ while (addr <= ullend) {
+ asm __volatile__ ("ocbp %0, 0" : : "r" (addr));
+ addr += L1_CACHE_BYTES;
+ }
+ return;
+}
+
+/* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for
+ anything else in the kernel */
+#define MAGIC_PAGE0_START 0xffffffffec000000ULL
+
+static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr)
+{
+ /* Purge the physical page 'paddr' from the cache. It's known that any
+ cache lines requiring attention have the same page colour as the the
+ address 'eaddr'.
+
+ This relies on the fact that the D-cache matches on physical tags
+ when no virtual tag matches. So we create an alias for the original
+ page and purge through that. (Alternatively, we could have done
+ this by switching ASID to match the original mapping and purged
+ through that, but that involves ASID switching cost + probably a
+ TLBMISS + refill anyway.)
+ */
+
+ unsigned long long magic_page_start;
+ unsigned long long magic_eaddr, magic_eaddr_end;
+
+ magic_page_start = MAGIC_PAGE0_START + (eaddr & CACHE_OC_SYN_MASK);
+
+ /* As long as the kernel is not pre-emptible, this doesn't need to be
+ under cli/sti. */
+
+ sh64_setup_dtlb_cache_slot(magic_page_start, get_asid(), paddr);
+
+ magic_eaddr = magic_page_start;
+ magic_eaddr_end = magic_eaddr + PAGE_SIZE;
+ while (magic_eaddr < magic_eaddr_end) {
+ /* Little point in unrolling this loop - the OCBPs are blocking
+ and won't go any quicker (i.e. the loop overhead is parallel
+ to part of the OCBP execution.) */
+ asm __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr));
+ magic_eaddr += L1_CACHE_BYTES;
+ }
+
+ sh64_teardown_dtlb_cache_slot();
+}
+
+/****************************************************************************/
+
+static void sh64_dcache_purge_phy_page(unsigned long paddr)
+{
+ /* Pure a page given its physical start address, by creating a
+ temporary 1 page mapping and purging across that. Even if we know
+ the virtual address (& vma or mm) of the page, the method here is
+ more elegant because it avoids issues of coping with page faults on
+ the purge instructions (i.e. no special-case code required in the
+ critical path in the TLB miss handling). */
+
+ unsigned long long eaddr_start, eaddr, eaddr_end;
+ int i;
+
+ /* As long as the kernel is not pre-emptible, this doesn't need to be
+ under cli/sti. */
+
+ eaddr_start = MAGIC_PAGE0_START;
+ for (i=0; i < (1 << CACHE_OC_N_SYNBITS); i++) {
+ sh64_setup_dtlb_cache_slot(eaddr_start, get_asid(), paddr);
+
+ eaddr = eaddr_start;
+ eaddr_end = eaddr + PAGE_SIZE;
+ while (eaddr < eaddr_end) {
+ asm __volatile__ ("ocbp %0, 0" : : "r" (eaddr));
+ eaddr += L1_CACHE_BYTES;
+ }
+
+ sh64_teardown_dtlb_cache_slot();
+ eaddr_start += PAGE_SIZE;
+ }
+}
+
+static void sh64_dcache_purge_user_pages(struct mm_struct *mm,
+ unsigned long addr, unsigned long end)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+ spinlock_t *ptl;
+ unsigned long paddr;
+
+ if (!mm)
+ return; /* No way to find physical address of page */
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd_bad(*pgd))
+ return;
+
+ pmd = pmd_offset(pgd, addr);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ return;
+
+ pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ do {
+ entry = *pte;
+ if (pte_none(entry) || !pte_present(entry))
+ continue;
+ paddr = pte_val(entry) & PAGE_MASK;
+ sh64_dcache_purge_coloured_phy_page(paddr, addr);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ pte_unmap_unlock(pte - 1, ptl);
+}
+/****************************************************************************/
+
+static void sh64_dcache_purge_user_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ /* There are at least 5 choices for the implementation of this, with
+ pros (+), cons(-), comments(*):
+
+ 1. ocbp each line in the range through the original user's ASID
+ + no lines spuriously evicted
+ - tlbmiss handling (must either handle faults on demand => extra
+ special-case code in tlbmiss critical path), or map the page in
+ advance (=> flush_tlb_range in advance to avoid multiple hits)
+ - ASID switching
+ - expensive for large ranges
+
+ 2. temporarily map each page in the range to a special effective
+ address and ocbp through the temporary mapping; relies on the
+ fact that SH-5 OCB* always do TLB lookup and match on ptags (they
+ never look at the etags)
+ + no spurious evictions
+ - expensive for large ranges
+ * surely cheaper than (1)
+
+ 3. walk all the lines in the cache, check the tags, if a match
+ occurs create a page mapping to ocbp the line through
+ + no spurious evictions
+ - tag inspection overhead
+ - (especially for small ranges)
+ - potential cost of setting up/tearing down page mapping for
+ every line that matches the range
+ * cost partly independent of range size
+
+ 4. walk all the lines in the cache, check the tags, if a match
+ occurs use 4 * alloco to purge the line (+3 other probably
+ innocent victims) by natural eviction
+ + no tlb mapping overheads
+ - spurious evictions
+ - tag inspection overhead
+
+ 5. implement like flush_cache_all
+ + no tag inspection overhead
+ - spurious evictions
+ - bad for small ranges
+
+ (1) can be ruled out as more expensive than (2). (2) appears best
+ for small ranges. The choice between (3), (4) and (5) for large
+ ranges and the range size for the large/small boundary need
+ benchmarking to determine.
+
+ For now use approach (2) for small ranges and (5) for large ones.
+
+ */
+
+ int n_pages;
+
+ n_pages = ((end - start) >> PAGE_SHIFT);
+ if (n_pages >= 64 || ((start ^ (end - 1)) & PMD_MASK)) {
+#if 1
+ sh64_dcache_purge_all();
+#else
+ unsigned long long set, way;
+ unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+ for (set = 0; set < cpu_data->dcache.sets; set++) {
+ unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift);
+ for (way = 0; way < cpu_data->dcache.ways; way++) {
+ unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift);
+ unsigned long long tag0;
+ unsigned long line_valid;
+
+ asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr));
+ line_valid = tag0 & SH_CACHE_VALID;
+ if (line_valid) {
+ unsigned long cache_asid;
+ unsigned long epn;
+
+ cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift;
+ /* The next line needs some
+ explanation. The virtual tags
+ encode bits [31:13] of the virtual
+ address, bit [12] of the 'tag' being
+ implied by the cache set index. */
+ epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift);
+
+ if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) {
+ /* TODO : could optimise this
+ call by batching multiple
+ adjacent sets together. */
+ sh64_dcache_purge_sets(set, 1);
+ break; /* Don't waste time inspecting other ways for this set */
+ }
+ }
+ }
+ }
+#endif
+ } else {
+ /* Small range, covered by a single page table page */
+ start &= PAGE_MASK; /* should already be so */
+ end = PAGE_ALIGN(end); /* should already be so */
+ sh64_dcache_purge_user_pages(mm, start, end);
+ }
+ return;
+}
+
+static void sh64_dcache_wback_current_user_range(unsigned long start, unsigned long end)
+{
+ unsigned long long aligned_start;
+ unsigned long long ull_end;
+ unsigned long long addr;
+
+ ull_end = end;
+
+ /* Just wback over the range using the natural addresses. TLB miss
+ handling will be OK (TBC) : the range has just been written to by
+ the signal frame setup code, so the PTEs must exist.
+
+ Note, if we have CONFIG_PREEMPT and get preempted inside this loop,
+ it doesn't matter, even if the pid->ASID mapping changes whilst
+ we're away. In that case the cache will have been flushed when the
+ mapping was renewed. So the writebacks below will be nugatory (and
+ we'll doubtless have to fault the TLB entry/ies in again with the
+ new ASID), but it's a rare case.
+ */
+ aligned_start = start & L1_CACHE_ALIGN_MASK;
+ addr = aligned_start;
+ while (addr < ull_end) {
+ asm __volatile__ ("ocbwb %0, 0" : : "r" (addr));
+ addr += L1_CACHE_BYTES;
+ }
+}
+
+/****************************************************************************/
+
+/* These *MUST* lie in an area of virtual address space that's otherwise unused. */
+#define UNIQUE_EADDR_START 0xe0000000UL
+#define UNIQUE_EADDR_END 0xe8000000UL
+
+static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr)
+{
+ /* Given a physical address paddr, and a user virtual address
+ user_eaddr which will eventually be mapped to it, create a one-off
+ kernel-private eaddr mapped to the same paddr. This is used for
+ creating special destination pages for copy_user_page and
+ clear_user_page */
+
+ static unsigned long current_pointer = UNIQUE_EADDR_START;
+ unsigned long coloured_pointer;
+
+ if (current_pointer == UNIQUE_EADDR_END) {
+ sh64_dcache_purge_all();
+ current_pointer = UNIQUE_EADDR_START;
+ }
+
+ coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | (user_eaddr & CACHE_OC_SYN_MASK);
+ sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr);
+
+ current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS);
+
+ return coloured_pointer;
+}
+
+/****************************************************************************/
+
+static void sh64_copy_user_page_coloured(void *to, void *from, unsigned long address)
+{
+ void *coloured_to;
+
+ /* Discard any existing cache entries of the wrong colour. These are
+ present quite often, if the kernel has recently used the page
+ internally, then given it up, then it's been allocated to the user.
+ */
+ sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
+
+ coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
+ sh64_page_copy(from, coloured_to);
+
+ sh64_teardown_dtlb_cache_slot();
+}
+
+static void sh64_clear_user_page_coloured(void *to, unsigned long address)
+{
+ void *coloured_to;
+
+ /* Discard any existing kernel-originated lines of the wrong colour (as
+ above) */
+ sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
+
+ coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
+ sh64_page_clear(coloured_to);
+
+ sh64_teardown_dtlb_cache_slot();
+}
+
+#endif /* !CONFIG_DCACHE_DISABLED */
+
+/****************************************************************************/
+
+/*##########################################################################
+ EXTERNALLY CALLABLE API.
+ ##########################################################################*/
+
+/* These functions are described in Documentation/cachetlb.txt.
+ Each one of these functions varies in behaviour depending on whether the
+ I-cache and/or D-cache are configured out.
+
+ Note that the Linux term 'flush' corresponds to what is termed 'purge' in
+ the sh/sh64 jargon for the D-cache, i.e. write back dirty data then
+ invalidate the cache lines, and 'invalidate' for the I-cache.
+ */
+
+#undef FLUSH_TRACE
+
+void flush_cache_all(void)
+{
+ /* Invalidate the entire contents of both caches, after writing back to
+ memory any dirty data from the D-cache. */
+ sh64_dcache_purge_all();
+ sh64_icache_inv_all();
+}
+
+/****************************************************************************/
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ /* Invalidate an entire user-address space from both caches, after
+ writing back dirty data (e.g. for shared mmap etc). */
+
+ /* This could be coded selectively by inspecting all the tags then
+ doing 4*alloco on any set containing a match (as for
+ flush_cache_range), but fork/exit/execve (where this is called from)
+ are expensive anyway. */
+
+ /* Have to do a purge here, despite the comments re I-cache below.
+ There could be odd-coloured dirty data associated with the mm still
+ in the cache - if this gets written out through natural eviction
+ after the kernel has reused the page there will be chaos.
+ */
+
+ sh64_dcache_purge_all();
+
+ /* The mm being torn down won't ever be active again, so any Icache
+ lines tagged with its ASID won't be visible for the rest of the
+ lifetime of this ASID cycle. Before the ASID gets reused, there
+ will be a flush_cache_all. Hence we don't need to touch the
+ I-cache. This is similar to the lack of action needed in
+ flush_tlb_mm - see fault.c. */
+}
+
+/****************************************************************************/
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ /* Invalidate (from both caches) the range [start,end) of virtual
+ addresses from the user address space specified by mm, after writing
+ back any dirty data.
+
+ Note, 'end' is 1 byte beyond the end of the range to flush. */
+
+ sh64_dcache_purge_user_range(mm, start, end);
+ sh64_icache_inv_user_page_range(mm, start, end);
+}
+
+/****************************************************************************/
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, unsigned long pfn)
+{
+ /* Invalidate any entries in either cache for the vma within the user
+ address space vma->vm_mm for the page starting at virtual address
+ 'eaddr'. This seems to be used primarily in breaking COW. Note,
+ the I-cache must be searched too in case the page in question is
+ both writable and being executed from (e.g. stack trampolines.)
+
+ Note, this is called with pte lock held.
+ */
+
+ sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT);
+
+ if (vma->vm_flags & VM_EXEC) {
+ sh64_icache_inv_user_page(vma, eaddr);
+ }
+}
+
+/****************************************************************************/
+
+#ifndef CONFIG_DCACHE_DISABLED
+
+void copy_user_page(void *to, void *from, unsigned long address, struct page *page)
+{
+ /* 'from' and 'to' are kernel virtual addresses (within the superpage
+ mapping of the physical RAM). 'address' is the user virtual address
+ where the copy 'to' will be mapped after. This allows a custom
+ mapping to be used to ensure that the new copy is placed in the
+ right cache sets for the user to see it without having to bounce it
+ out via memory. Note however : the call to flush_page_to_ram in
+ (generic)/mm/memory.c:(break_cow) undoes all this good work in that one
+ very important case!
+
+ TBD : can we guarantee that on every call, any cache entries for
+ 'from' are in the same colour sets as 'address' also? i.e. is this
+ always used just to deal with COW? (I suspect not). */
+
+ /* There are two possibilities here for when the page 'from' was last accessed:
+ * by the kernel : this is OK, no purge required.
+ * by the/a user (e.g. for break_COW) : need to purge.
+
+ If the potential user mapping at 'address' is the same colour as
+ 'from' there is no need to purge any cache lines from the 'from'
+ page mapped into cache sets of colour 'address'. (The copy will be
+ accessing the page through 'from').
+ */
+
+ if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) {
+ sh64_dcache_purge_coloured_phy_page(__pa(from), address);
+ }
+
+ if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
+ /* No synonym problem on destination */
+ sh64_page_copy(from, to);
+ } else {
+ sh64_copy_user_page_coloured(to, from, address);
+ }
+
+ /* Note, don't need to flush 'from' page from the cache again - it's
+ done anyway by the generic code */
+}
+
+void clear_user_page(void *to, unsigned long address, struct page *page)
+{
+ /* 'to' is a kernel virtual address (within the superpage
+ mapping of the physical RAM). 'address' is the user virtual address
+ where the 'to' page will be mapped after. This allows a custom
+ mapping to be used to ensure that the new copy is placed in the
+ right cache sets for the user to see it without having to bounce it
+ out via memory.
+ */
+
+ if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
+ /* No synonym problem on destination */
+ sh64_page_clear(to);
+ } else {
+ sh64_clear_user_page_coloured(to, address);
+ }
+}
+
+#endif /* !CONFIG_DCACHE_DISABLED */
+
+/****************************************************************************/
+
+void flush_dcache_page(struct page *page)
+{
+ sh64_dcache_purge_phy_page(page_to_phys(page));
+ wmb();
+}
+
+/****************************************************************************/
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ /* Flush the range [start,end] of kernel virtual adddress space from
+ the I-cache. The corresponding range must be purged from the
+ D-cache also because the SH-5 doesn't have cache snooping between
+ the caches. The addresses will be visible through the superpage
+ mapping, therefore it's guaranteed that there no cache entries for
+ the range in cache sets of the wrong colour.
+
+ Primarily used for cohering the I-cache after a module has
+ been loaded. */
+
+ /* We also make sure to purge the same range from the D-cache since
+ flush_page_to_ram() won't be doing this for us! */
+
+ sh64_dcache_purge_kernel_range(start, end);
+ wmb();
+ sh64_icache_inv_kernel_range(start, end);
+}
+
+/****************************************************************************/
+
+void flush_icache_user_range(struct vm_area_struct *vma,
+ struct page *page, unsigned long addr, int len)
+{
+ /* Flush the range of user (defined by vma->vm_mm) address space
+ starting at 'addr' for 'len' bytes from the cache. The range does
+ not straddle a page boundary, the unique physical page containing
+ the range is 'page'. This seems to be used mainly for invalidating
+ an address range following a poke into the program text through the
+ ptrace() call from another process (e.g. for BRK instruction
+ insertion). */
+
+ sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr);
+ mb();
+
+ if (vma->vm_flags & VM_EXEC) {
+ sh64_icache_inv_user_small_range(vma->vm_mm, addr, len);
+ }
+}
+
+/*##########################################################################
+ ARCH/SH64 PRIVATE CALLABLE API.
+ ##########################################################################*/
+
+void flush_cache_sigtramp(unsigned long start, unsigned long end)
+{
+ /* For the address range [start,end), write back the data from the
+ D-cache and invalidate the corresponding region of the I-cache for
+ the current process. Used to flush signal trampolines on the stack
+ to make them executable. */
+
+ sh64_dcache_wback_current_user_range(start, end);
+ wmb();
+ sh64_icache_inv_current_user_range(start, end);
+}
+
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index 4896d7376926..22dacc778823 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -71,7 +71,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
/*
* Writeback&Invalidate the D-cache of the page
*/
-static void __flush_dcache_page(unsigned long phys)
+static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys)
{
unsigned long ways, waysize, addrstart;
unsigned long flags;
@@ -92,7 +92,7 @@ static void __flush_dcache_page(unsigned long phys)
* possible.
*/
local_irq_save(flags);
- jump_to_P2();
+ jump_to_uncached();
ways = current_cpu_data.dcache.ways;
waysize = current_cpu_data.dcache.sets;
@@ -118,7 +118,7 @@ static void __flush_dcache_page(unsigned long phys)
addrstart += current_cpu_data.dcache.way_incr;
} while (--ways);
- back_to_P1();
+ back_to_cached();
local_irq_restore(flags);
}
@@ -132,15 +132,15 @@ void flush_dcache_page(struct page *page)
__flush_dcache_page(PHYSADDR(page_address(page)));
}
-void flush_cache_all(void)
+void __uses_jump_to_uncached flush_cache_all(void)
{
unsigned long flags;
local_irq_save(flags);
- jump_to_P2();
+ jump_to_uncached();
cache_wback_all();
- back_to_P1();
+ back_to_cached();
local_irq_restore(flags);
}
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index e220c29a3c00..7b2131c9eeda 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -1,7 +1,9 @@
/*
* arch/sh/mm/consistent.c
*
- * Copyright (C) 2004 Paul Mundt
+ * Copyright (C) 2004 - 2007 Paul Mundt
+ *
+ * Declared coherent memory functions based on arch/x86/kernel/pci-dma_32.c
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -13,58 +15,152 @@
#include <asm/addrspace.h>
#include <asm/io.h>
-void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
+struct dma_coherent_mem {
+ void *virt_base;
+ u32 device_base;
+ int size;
+ int flags;
+ unsigned long *bitmap;
+};
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
- struct page *page, *end, *free;
void *ret;
- int order;
+ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+ int order = get_order(size);
- size = PAGE_ALIGN(size);
- order = get_order(size);
+ if (mem) {
+ int page = bitmap_find_free_region(mem->bitmap, mem->size,
+ order);
+ if (page >= 0) {
+ *dma_handle = mem->device_base + (page << PAGE_SHIFT);
+ ret = mem->virt_base + (page << PAGE_SHIFT);
+ memset(ret, 0, size);
+ return ret;
+ }
+ if (mem->flags & DMA_MEMORY_EXCLUSIVE)
+ return NULL;
+ }
- page = alloc_pages(gfp, order);
- if (!page)
- return NULL;
- split_page(page, order);
+ ret = (void *)__get_free_pages(gfp, order);
- ret = page_address(page);
- memset(ret, 0, size);
- *handle = virt_to_phys(ret);
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ /*
+ * Pages from the page allocator may have data present in
+ * cache. So flush the cache before using uncached memory.
+ */
+ dma_cache_sync(NULL, ret, size, DMA_BIDIRECTIONAL);
+ *dma_handle = virt_to_phys(ret);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
- /*
- * We must flush the cache before we pass it on to the device
- */
- __flush_purge_region(ret, size);
+void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+ int order = get_order(size);
- page = virt_to_page(ret);
- free = page + (size >> PAGE_SHIFT);
- end = page + (1 << order);
+ if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+ int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
- while (++page < end) {
- /* Free any unused pages */
- if (page >= free) {
- __free_page(page);
- }
+ bitmap_release_region(mem->bitmap, page, order);
+ } else {
+ WARN_ON(irqs_disabled()); /* for portability */
+ BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE);
+ free_pages((unsigned long)vaddr, order);
}
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size, int flags)
+{
+ void __iomem *mem_base = NULL;
+ int pages = size >> PAGE_SHIFT;
+ int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+
+ if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
+ goto out;
+ if (!size)
+ goto out;
+ if (dev->dma_mem)
+ goto out;
+
+ /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
- return P2SEGADDR(ret);
+ mem_base = ioremap_nocache(bus_addr, size);
+ if (!mem_base)
+ goto out;
+
+ dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+ if (!dev->dma_mem)
+ goto out;
+ dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!dev->dma_mem->bitmap)
+ goto free1_out;
+
+ dev->dma_mem->virt_base = mem_base;
+ dev->dma_mem->device_base = device_addr;
+ dev->dma_mem->size = pages;
+ dev->dma_mem->flags = flags;
+
+ if (flags & DMA_MEMORY_MAP)
+ return DMA_MEMORY_MAP;
+
+ return DMA_MEMORY_IO;
+
+ free1_out:
+ kfree(dev->dma_mem);
+ out:
+ if (mem_base)
+ iounmap(mem_base);
+ return 0;
}
+EXPORT_SYMBOL(dma_declare_coherent_memory);
-void consistent_free(void *vaddr, size_t size)
+void dma_release_declared_memory(struct device *dev)
{
- unsigned long addr = P1SEGADDR((unsigned long)vaddr);
- struct page *page=virt_to_page(addr);
- int num_pages=(size+PAGE_SIZE-1) >> PAGE_SHIFT;
- int i;
+ struct dma_coherent_mem *mem = dev->dma_mem;
- for(i=0;i<num_pages;i++) {
- __free_page((page+i));
- }
+ if (!mem)
+ return;
+ dev->dma_mem = NULL;
+ iounmap(mem->virt_base);
+ kfree(mem->bitmap);
+ kfree(mem);
}
+EXPORT_SYMBOL(dma_release_declared_memory);
-void consistent_sync(void *vaddr, size_t size, int direction)
+void *dma_mark_declared_memory_occupied(struct device *dev,
+ dma_addr_t device_addr, size_t size)
{
- void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
+ struct dma_coherent_mem *mem = dev->dma_mem;
+ int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ int pos, err;
+
+ if (!mem)
+ return ERR_PTR(-EINVAL);
+
+ pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
+ err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
+ if (err != 0)
+ return ERR_PTR(err);
+ return mem->virt_base + (pos << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
+
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_CPU_SH5
+ void *p1addr = vaddr;
+#else
+ void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
+#endif
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
@@ -80,8 +176,4 @@ void consistent_sync(void *vaddr, size_t size, int direction)
BUG();
}
}
-
-EXPORT_SYMBOL(consistent_alloc);
-EXPORT_SYMBOL(consistent_free);
-EXPORT_SYMBOL(consistent_sync);
-
+EXPORT_SYMBOL(dma_cache_sync);
diff --git a/arch/sh/mm/extable.c b/arch/sh/mm/extable_32.c
index c1cf4463d09d..c1cf4463d09d 100644
--- a/arch/sh/mm/extable.c
+++ b/arch/sh/mm/extable_32.c
diff --git a/arch/sh/mm/extable_64.c b/arch/sh/mm/extable_64.c
new file mode 100644
index 000000000000..f05499688d88
--- /dev/null
+++ b/arch/sh/mm/extable_64.c
@@ -0,0 +1,82 @@
+/*
+ * arch/sh/mm/extable_64.c
+ *
+ * Copyright (C) 2003 Richard Curnow
+ * Copyright (C) 2003, 2004 Paul Mundt
+ *
+ * Cloned from the 2.5 SH version..
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
+extern void __copy_user_fixup(void);
+
+static const struct exception_table_entry __copy_user_fixup_ex = {
+ .fixup = (unsigned long)&__copy_user_fixup,
+};
+
+/*
+ * Some functions that may trap due to a bad user-mode address have too
+ * many loads and stores in them to make it at all practical to label
+ * each one and put them all in the main exception table.
+ *
+ * In particular, the fast memcpy routine is like this. It's fix-up is
+ * just to fall back to a slow byte-at-a-time copy, which is handled the
+ * conventional way. So it's functionally OK to just handle any trap
+ * occurring in the fast memcpy with that fixup.
+ */
+static const struct exception_table_entry *check_exception_ranges(unsigned long addr)
+{
+ if ((addr >= (unsigned long)&copy_user_memcpy) &&
+ (addr <= (unsigned long)&copy_user_memcpy_end))
+ return &__copy_user_fixup_ex;
+
+ return NULL;
+}
+
+/* Simple binary search */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ const struct exception_table_entry *mid;
+
+ mid = check_exception_ranges(value);
+ if (mid)
+ return mid;
+
+ while (first <= last) {
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+
+ return NULL;
+}
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault_32.c
index 60d74f793a1d..33b43d20e9f6 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault_32.c
@@ -172,7 +172,7 @@ no_context:
bust_spinlocks(1);
if (oops_may_print()) {
- __typeof__(pte_val(__pte(0))) page;
+ unsigned long page;
if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL "
diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
new file mode 100644
index 000000000000..399d53710d2f
--- /dev/null
+++ b/arch/sh/mm/fault_64.c
@@ -0,0 +1,275 @@
+/*
+ * The SH64 TLB miss.
+ *
+ * Original code from fault.c
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * Fast PTE->TLB refill path
+ * Copyright (C) 2003 Richard.Curnow@superh.com
+ *
+ * IMPORTANT NOTES :
+ * The do_fast_page_fault function is called from a context in entry.S
+ * where very few registers have been saved. In particular, the code in
+ * this file must be compiled not to use ANY caller-save registers that
+ * are not part of the restricted save set. Also, it means that code in
+ * this file must not make calls to functions elsewhere in the kernel, or
+ * else the excepting context will see corruption in its caller-save
+ * registers. Plus, the entry.S save area is non-reentrant, so this code
+ * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
+ * on any exception.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/tlb.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/cpu/registers.h>
+
+/* Callable from fault.c, so not static */
+inline void __do_tlb_refill(unsigned long address,
+ unsigned long long is_text_not_data, pte_t *pte)
+{
+ unsigned long long ptel;
+ unsigned long long pteh=0;
+ struct tlb_info *tlbp;
+ unsigned long long next;
+
+ /* Get PTEL first */
+ ptel = pte_val(*pte);
+
+ /*
+ * Set PTEH register
+ */
+ pteh = address & MMU_VPN_MASK;
+
+ /* Sign extend based on neff. */
+#if (NEFF == 32)
+ /* Faster sign extension */
+ pteh = (unsigned long long)(signed long long)(signed long)pteh;
+#else
+ /* General case */
+ pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh;
+#endif
+
+ /* Set the ASID. */
+ pteh |= get_asid() << PTEH_ASID_SHIFT;
+ pteh |= PTEH_VALID;
+
+ /* Set PTEL register, set_pte has performed the sign extension */
+ ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+
+ tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
+ next = tlbp->next;
+ __flush_tlb_slot(next);
+ asm volatile ("putcfg %0,1,%2\n\n\t"
+ "putcfg %0,0,%1\n"
+ : : "r" (next), "r" (pteh), "r" (ptel) );
+
+ next += TLB_STEP;
+ if (next > tlbp->last) next = tlbp->first;
+ tlbp->next = next;
+
+}
+
+static int handle_vmalloc_fault(struct mm_struct *mm,
+ unsigned long protection_flags,
+ unsigned long long textaccess,
+ unsigned long address)
+{
+ pgd_t *dir;
+ pud_t *pud;
+ pmd_t *pmd;
+ static pte_t *pte;
+ pte_t entry;
+
+ dir = pgd_offset_k(address);
+
+ pud = pud_offset(dir, address);
+ if (pud_none_or_clear_bad(pud))
+ return 0;
+
+ pmd = pmd_offset(pud, address);
+ if (pmd_none_or_clear_bad(pmd))
+ return 0;
+
+ pte = pte_offset_kernel(pmd, address);
+ entry = *pte;
+
+ if (pte_none(entry) || !pte_present(entry))
+ return 0;
+ if ((pte_val(entry) & protection_flags) != protection_flags)
+ return 0;
+
+ __do_tlb_refill(address, textaccess, pte);
+
+ return 1;
+}
+
+static int handle_tlbmiss(struct mm_struct *mm,
+ unsigned long long protection_flags,
+ unsigned long long textaccess,
+ unsigned long address)
+{
+ pgd_t *dir;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+
+ /* NB. The PGD currently only contains a single entry - there is no
+ page table tree stored for the top half of the address space since
+ virtual pages in that region should never be mapped in user mode.
+ (In kernel mode, the only things in that region are the 512Mb super
+ page (locked in), and vmalloc (modules) + I/O device pages (handled
+ by handle_vmalloc_fault), so no PGD for the upper half is required
+ by kernel mode either).
+
+ See how mm->pgd is allocated and initialised in pgd_alloc to see why
+ the next test is necessary. - RPC */
+ if (address >= (unsigned long) TASK_SIZE)
+ /* upper half - never has page table entries. */
+ return 0;
+
+ dir = pgd_offset(mm, address);
+ if (pgd_none(*dir) || !pgd_present(*dir))
+ return 0;
+ if (!pgd_present(*dir))
+ return 0;
+
+ pud = pud_offset(dir, address);
+ if (pud_none(*pud) || !pud_present(*pud))
+ return 0;
+
+ pmd = pmd_offset(pud, address);
+ if (pmd_none(*pmd) || !pmd_present(*pmd))
+ return 0;
+
+ pte = pte_offset_kernel(pmd, address);
+ entry = *pte;
+
+ if (pte_none(entry) || !pte_present(entry))
+ return 0;
+
+ /*
+ * If the page doesn't have sufficient protection bits set to
+ * service the kind of fault being handled, there's not much
+ * point doing the TLB refill. Punt the fault to the general
+ * handler.
+ */
+ if ((pte_val(entry) & protection_flags) != protection_flags)
+ return 0;
+
+ __do_tlb_refill(address, textaccess, pte);
+
+ return 1;
+}
+
+/*
+ * Put all this information into one structure so that everything is just
+ * arithmetic relative to a single base address. This reduces the number
+ * of movi/shori pairs needed just to load addresses of static data.
+ */
+struct expevt_lookup {
+ unsigned short protection_flags[8];
+ unsigned char is_text_access[8];
+ unsigned char is_write_access[8];
+};
+
+#define PRU (1<<9)
+#define PRW (1<<8)
+#define PRX (1<<7)
+#define PRR (1<<6)
+
+#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
+#define YOUNG (_PAGE_ACCESSED)
+
+/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
+ the fault happened in user mode or privileged mode. */
+static struct expevt_lookup expevt_lookup_table = {
+ .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
+ .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ This routine handles page faults that can be serviced just by refilling a
+ TLB entry from an existing page table entry. (This case represents a very
+ large majority of page faults.) Return 1 if the fault was successfully
+ handled. Return 0 if the fault could not be handled. (This leads into the
+ general fault handling in fault.c which deals with mapping file-backed
+ pages, stack growth, segmentation faults, swapping etc etc)
+ */
+asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
+ unsigned long long expevt,
+ unsigned long address)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ unsigned long long textaccess;
+ unsigned long long protection_flags;
+ unsigned long long index;
+ unsigned long long expevt4;
+
+ /* The next few lines implement a way of hashing EXPEVT into a
+ * small array index which can be used to lookup parameters
+ * specific to the type of TLBMISS being handled.
+ *
+ * Note:
+ * ITLBMISS has EXPEVT==0xa40
+ * RTLBMISS has EXPEVT==0x040
+ * WTLBMISS has EXPEVT==0x060
+ */
+ expevt4 = (expevt >> 4);
+ /* TODO : xor ssr_md into this expression too. Then we can check
+ * that PRU is set when it needs to be. */
+ index = expevt4 ^ (expevt4 >> 5);
+ index &= 7;
+ protection_flags = expevt_lookup_table.protection_flags[index];
+ textaccess = expevt_lookup_table.is_text_access[index];
+
+ /* SIM
+ * Note this is now called with interrupts still disabled
+ * This is to cope with being called for a missing IO port
+ * address with interrupts disabled. This should be fixed as
+ * soon as we have a better 'fast path' miss handler.
+ *
+ * Plus take care how you try and debug this stuff.
+ * For example, writing debug data to a port which you
+ * have just faulted on is not going to work.
+ */
+
+ tsk = current;
+ mm = tsk->mm;
+
+ if ((address >= VMALLOC_START && address < VMALLOC_END) ||
+ (address >= IOBASE_VADDR && address < IOBASE_END)) {
+ if (ssr_md)
+ /*
+ * Process-contexts can never have this address
+ * range mapped
+ */
+ if (handle_vmalloc_fault(mm, protection_flags,
+ textaccess, address))
+ return 1;
+ } else if (!in_interrupt() && mm) {
+ if (handle_tlbmiss(mm, protection_flags, textaccess, address))
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index d5e160da64b2..2918c6b14659 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -23,9 +23,7 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-void (*copy_page)(void *from, void *to);
-void (*clear_page)(void *to);
+unsigned long cached_to_uncached = 0;
void show_mem(void)
{
@@ -102,7 +100,8 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
- flush_tlb_one(get_asid(), addr);
+ if (cached_to_uncached)
+ flush_tlb_one(get_asid(), addr);
}
/*
@@ -131,6 +130,37 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
set_pte_phys(address, phys, prot);
}
+
+void __init page_table_range_init(unsigned long start, unsigned long end,
+ pgd_t *pgd_base)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ int pgd_idx;
+ unsigned long vaddr;
+
+ vaddr = start & PMD_MASK;
+ end = (end + PMD_SIZE - 1) & PMD_MASK;
+ pgd_idx = pgd_index(vaddr);
+ pgd = pgd_base + pgd_idx;
+
+ for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
+ BUG_ON(pgd_none(*pgd));
+ pud = pud_offset(pgd, 0);
+ BUG_ON(pud_none(*pud));
+ pmd = pmd_offset(pud, 0);
+
+ if (!pmd_present(*pmd)) {
+ pte_t *pte_table;
+ pte_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+ memset(pte_table, 0, PAGE_SIZE);
+ pmd_populate_kernel(&init_mm, pmd, pte_table);
+ }
+
+ vaddr += PMD_SIZE;
+ }
+}
#endif /* CONFIG_MMU */
/*
@@ -150,6 +180,11 @@ void __init paging_init(void)
* check for a null value. */
set_TTB(swapper_pg_dir);
+ /* Populate the relevant portions of swapper_pg_dir so that
+ * we can use the fixmap entries without calling kmalloc.
+ * pte's will be filled in by __set_fixmap(). */
+ page_table_range_init(FIXADDR_START, FIXADDR_TOP, swapper_pg_dir);
+
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
for_each_online_node(nid) {
@@ -167,9 +202,22 @@ void __init paging_init(void)
}
free_area_init_nodes(max_zone_pfns);
+
+ /* Set up the uncached fixmap */
+ set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
+
+#ifdef CONFIG_29BIT
+ /*
+ * Handle trivial transitions between cached and uncached
+ * segments, making use of the 1:1 mapping relationship in
+ * 512MB lowmem.
+ */
+ cached_to_uncached = P2SEG - P1SEG;
+#endif
}
static struct kcore_list kcore_mem, kcore_vmalloc;
+int after_bootmem = 0;
void __init mem_init(void)
{
@@ -202,17 +250,7 @@ void __init mem_init(void)
memset(empty_zero_page, 0, PAGE_SIZE);
__flush_wback_region(empty_zero_page, PAGE_SIZE);
- /*
- * Setup wrappers for copy/clear_page(), these will get overridden
- * later in the boot process if a better method is available.
- */
-#ifdef CONFIG_MMU
- copy_page = copy_page_slow;
- clear_page = clear_page_slow;
-#else
- copy_page = copy_page_nommu;
- clear_page = clear_page_nommu;
-#endif
+ after_bootmem = 1;
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap_32.c
index 0c7b7e33abdc..0c7b7e33abdc 100644
--- a/arch/sh/mm/ioremap.c
+++ b/arch/sh/mm/ioremap_32.c
diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c
new file mode 100644
index 000000000000..e27d16519235
--- /dev/null
+++ b/arch/sh/mm/ioremap_64.c
@@ -0,0 +1,404 @@
+/*
+ * arch/sh/mm/ioremap_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * Mostly derived from arch/sh/mm/ioremap.c which, in turn is mostly
+ * derived from arch/i386/mm/ioremap.c .
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/vmalloc.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/bootmem.h>
+#include <linux/proc_fs.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/addrspace.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu.h>
+
+static void shmedia_mapioaddr(unsigned long, unsigned long);
+static unsigned long shmedia_ioremap(struct resource *, u32, int);
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void *__ioremap(unsigned long phys_addr, unsigned long size,
+ unsigned long flags)
+{
+ void * addr;
+ struct vm_struct * area;
+ unsigned long offset, last_addr;
+ pgprot_t pgprot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+ if (!size || last_addr < phys_addr)
+ return NULL;
+
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
+ _PAGE_WRITE | _PAGE_DIRTY |
+ _PAGE_ACCESSED | _PAGE_SHARED | flags);
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ phys_addr &= PAGE_MASK;
+ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ pr_debug("Get vm_area returns %p addr %p\n",area,area->addr);
+ if (!area)
+ return NULL;
+ area->phys_addr = phys_addr;
+ addr = area->addr;
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
+ vunmap(addr);
+ return NULL;
+ }
+ return (void *) (offset + (char *)addr);
+}
+EXPORT_SYMBOL(__ioremap);
+
+void __iounmap(void *addr)
+{
+ struct vm_struct *area;
+
+ vfree((void *) (PAGE_MASK & (unsigned long) addr));
+ area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
+ if (!area) {
+ printk(KERN_ERR "iounmap: bad address %p\n", addr);
+ return;
+ }
+
+ kfree(area);
+}
+EXPORT_SYMBOL(__iounmap);
+
+static struct resource shmedia_iomap = {
+ .name = "shmedia_iomap",
+ .start = IOBASE_VADDR + PAGE_SIZE,
+ .end = IOBASE_END - 1,
+};
+
+static void shmedia_mapioaddr(unsigned long pa, unsigned long va);
+static void shmedia_unmapioaddr(unsigned long vaddr);
+static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz);
+
+/*
+ * We have the same problem as the SPARC, so lets have the same comment:
+ * Our mini-allocator...
+ * Boy this is gross! We need it because we must map I/O for
+ * timers and interrupt controller before the kmalloc is available.
+ */
+
+#define XNMLN 15
+#define XNRES 10
+
+struct xresource {
+ struct resource xres; /* Must be first */
+ int xflag; /* 1 == used */
+ char xname[XNMLN+1];
+};
+
+static struct xresource xresv[XNRES];
+
+static struct xresource *xres_alloc(void)
+{
+ struct xresource *xrp;
+ int n;
+
+ xrp = xresv;
+ for (n = 0; n < XNRES; n++) {
+ if (xrp->xflag == 0) {
+ xrp->xflag = 1;
+ return xrp;
+ }
+ xrp++;
+ }
+ return NULL;
+}
+
+static void xres_free(struct xresource *xrp)
+{
+ xrp->xflag = 0;
+}
+
+static struct resource *shmedia_find_resource(struct resource *root,
+ unsigned long vaddr)
+{
+ struct resource *res;
+
+ for (res = root->child; res; res = res->sibling)
+ if (res->start <= vaddr && res->end >= vaddr)
+ return res;
+
+ return NULL;
+}
+
+static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size,
+ const char *name)
+{
+ static int printed_full = 0;
+ struct xresource *xres;
+ struct resource *res;
+ char *tack;
+ int tlen;
+
+ if (name == NULL) name = "???";
+
+ if ((xres = xres_alloc()) != 0) {
+ tack = xres->xname;
+ res = &xres->xres;
+ } else {
+ if (!printed_full) {
+ printk("%s: done with statics, switching to kmalloc\n",
+ __FUNCTION__);
+ printed_full = 1;
+ }
+ tlen = strlen(name);
+ tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
+ if (!tack)
+ return -ENOMEM;
+ memset(tack, 0, sizeof(struct resource));
+ res = (struct resource *) tack;
+ tack += sizeof (struct resource);
+ }
+
+ strncpy(tack, name, XNMLN);
+ tack[XNMLN] = 0;
+ res->name = tack;
+
+ return shmedia_ioremap(res, phys, size);
+}
+
+static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz)
+{
+ unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
+ unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
+ unsigned long va;
+ unsigned int psz;
+
+ if (allocate_resource(&shmedia_iomap, res, round_sz,
+ shmedia_iomap.start, shmedia_iomap.end,
+ PAGE_SIZE, NULL, NULL) != 0) {
+ panic("alloc_io_res(%s): cannot occupy\n",
+ (res->name != NULL)? res->name: "???");
+ }
+
+ va = res->start;
+ pa &= PAGE_MASK;
+
+ psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
+
+ /* log at boot time ... */
+ printk("mapioaddr: %6s [%2d page%s] va 0x%08lx pa 0x%08x\n",
+ ((res->name != NULL) ? res->name : "???"),
+ psz, psz == 1 ? " " : "s", va, pa);
+
+ for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
+ shmedia_mapioaddr(pa, va);
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ }
+
+ res->start += offset;
+ res->end = res->start + sz - 1; /* not strictly necessary.. */
+
+ return res->start;
+}
+
+static void shmedia_free_io(struct resource *res)
+{
+ unsigned long len = res->end - res->start + 1;
+
+ BUG_ON((len & (PAGE_SIZE - 1)) != 0);
+
+ while (len) {
+ len -= PAGE_SIZE;
+ shmedia_unmapioaddr(res->start + len);
+ }
+
+ release_resource(res);
+}
+
+static __init_refok void *sh64_get_page(void)
+{
+ extern int after_bootmem;
+ void *page;
+
+ if (after_bootmem) {
+ page = (void *)get_zeroed_page(GFP_ATOMIC);
+ } else {
+ page = alloc_bootmem_pages(PAGE_SIZE);
+ }
+
+ if (!page || ((unsigned long)page & ~PAGE_MASK))
+ panic("sh64_get_page: Out of memory already?\n");
+
+ return page;
+}
+
+static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+ pte_t *ptep, pte;
+ pgprot_t prot;
+ unsigned long flags = 1; /* 1 = CB0-1 device */
+
+ pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va);
+
+ pgdp = pgd_offset_k(va);
+ if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
+ pudp = (pud_t *)sh64_get_page();
+ set_pgd(pgdp, __pgd((unsigned long)pudp | _KERNPG_TABLE));
+ }
+
+ pudp = pud_offset(pgdp, va);
+ if (pud_none(*pudp) || !pud_present(*pudp)) {
+ pmdp = (pmd_t *)sh64_get_page();
+ set_pud(pudp, __pud((unsigned long)pmdp | _KERNPG_TABLE));
+ }
+
+ pmdp = pmd_offset(pudp, va);
+ if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) {
+ ptep = (pte_t *)sh64_get_page();
+ set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
+ }
+
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE |
+ _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SHARED | flags);
+
+ pte = pfn_pte(pa >> PAGE_SHIFT, prot);
+ ptep = pte_offset_kernel(pmdp, va);
+
+ if (!pte_none(*ptep) &&
+ pte_val(*ptep) != pte_val(pte))
+ pte_ERROR(*ptep);
+
+ set_pte(ptep, pte);
+
+ flush_tlb_kernel_range(va, PAGE_SIZE);
+}
+
+static void shmedia_unmapioaddr(unsigned long vaddr)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ pgdp = pgd_offset_k(vaddr);
+ if (pgd_none(*pgdp) || pgd_bad(*pgdp))
+ return;
+
+ pudp = pud_offset(pgdp, vaddr);
+ if (pud_none(*pudp) || pud_bad(*pudp))
+ return;
+
+ pmdp = pmd_offset(pudp, vaddr);
+ if (pmd_none(*pmdp) || pmd_bad(*pmdp))
+ return;
+
+ ptep = pte_offset_kernel(pmdp, vaddr);
+
+ if (pte_none(*ptep) || !pte_present(*ptep))
+ return;
+
+ clear_page((void *)ptep);
+ pte_clear(&init_mm, vaddr, ptep);
+}
+
+unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name)
+{
+ if (size < PAGE_SIZE)
+ size = PAGE_SIZE;
+
+ return shmedia_alloc_io(phys, size, name);
+}
+
+void onchip_unmap(unsigned long vaddr)
+{
+ struct resource *res;
+ unsigned int psz;
+
+ res = shmedia_find_resource(&shmedia_iomap, vaddr);
+ if (!res) {
+ printk(KERN_ERR "%s: Failed to free 0x%08lx\n",
+ __FUNCTION__, vaddr);
+ return;
+ }
+
+ psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
+
+ printk(KERN_DEBUG "unmapioaddr: %6s [%2d page%s] freed\n",
+ res->name, psz, psz == 1 ? " " : "s");
+
+ shmedia_free_io(res);
+
+ if ((char *)res >= (char *)xresv &&
+ (char *)res < (char *)&xresv[XNRES]) {
+ xres_free((struct xresource *)res);
+ } else {
+ kfree(res);
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+static int
+ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
+ void *data)
+{
+ char *p = buf, *e = buf + length;
+ struct resource *r;
+ const char *nm;
+
+ for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
+ if (p + 32 >= e) /* Better than nothing */
+ break;
+ if ((nm = r->name) == 0) nm = "???";
+ p += sprintf(p, "%08lx-%08lx: %s\n",
+ (unsigned long)r->start,
+ (unsigned long)r->end, nm);
+ }
+
+ return p-buf;
+}
+#endif /* CONFIG_PROC_FS */
+
+static int __init register_proc_onchip(void)
+{
+#ifdef CONFIG_PROC_FS
+ create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap);
+#endif
+ return 0;
+}
+
+__initcall(register_proc_onchip);
diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
index d15221beaa16..677dd57f0877 100644
--- a/arch/sh/mm/pg-nommu.c
+++ b/arch/sh/mm/pg-nommu.c
@@ -14,12 +14,12 @@
#include <linux/string.h>
#include <asm/page.h>
-void copy_page_nommu(void *to, void *from)
+void copy_page(void *to, void *from)
{
memcpy(to, from, PAGE_SIZE);
}
-void clear_page_nommu(void *to)
+void clear_page(void *to)
{
memset(to, 0, PAGE_SIZE);
}
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index 1d45b82f0a63..ab81c602295f 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -27,6 +27,7 @@
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/io.h>
+#include <asm/mmu_context.h>
#define NR_PMB_ENTRIES 16
@@ -162,18 +163,18 @@ repeat:
return 0;
}
-int set_pmb_entry(struct pmb_entry *pmbe)
+int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
{
int ret;
- jump_to_P2();
+ jump_to_uncached();
ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
- back_to_P1();
+ back_to_cached();
return ret;
}
-void clear_pmb_entry(struct pmb_entry *pmbe)
+void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
{
unsigned int entry = pmbe->entry;
unsigned long addr;
@@ -187,7 +188,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe)
entry >= NR_PMB_ENTRIES))
return;
- jump_to_P2();
+ jump_to_uncached();
/* Clear V-bit */
addr = mk_pmb_addr(entry);
@@ -196,7 +197,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe)
addr = mk_pmb_data(entry);
ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
- back_to_P1();
+ back_to_cached();
clear_bit(entry, &pmb_map);
}
@@ -301,17 +302,17 @@ static void pmb_cache_ctor(struct kmem_cache *cachep, void *pmb)
pmbe->entry = PMB_NO_ENTRY;
}
-static int __init pmb_init(void)
+static int __uses_jump_to_uncached pmb_init(void)
{
unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
- unsigned int entry;
+ unsigned int entry, i;
BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
SLAB_PANIC, pmb_cache_ctor);
- jump_to_P2();
+ jump_to_uncached();
/*
* Ordering is important, P2 must be mapped in the PMB before we
@@ -329,7 +330,12 @@ static int __init pmb_init(void)
/* PMB.SE and UB[7] */
ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
- back_to_P1();
+ /* Flush out the TLB */
+ i = ctrl_inl(MMUCR);
+ i |= MMUCR_TI;
+ ctrl_outl(i, MMUCR);
+
+ back_to_cached();
return 0;
}
diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c
index 1ccca7c0532e..15111bc7ddd6 100644
--- a/arch/sh/mm/tlb-nommu.c
+++ b/arch/sh/mm/tlb-nommu.c
@@ -9,6 +9,7 @@
*/
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <asm/pgtable.h>
/*
* Nothing too terribly exciting here ..
@@ -49,3 +50,12 @@ void update_mmu_cache(struct vm_area_struct * vma,
{
BUG();
}
+
+void __init page_table_range_init(unsigned long start, unsigned long end,
+ pgd_t *pgd_base)
+{
+}
+
+void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
+{
+}
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
index 2d1dd6044307..f0c7b7397fa6 100644
--- a/arch/sh/mm/tlb-sh4.c
+++ b/arch/sh/mm/tlb-sh4.c
@@ -79,7 +79,8 @@ void update_mmu_cache(struct vm_area_struct * vma,
local_irq_restore(flags);
}
-void local_flush_tlb_one(unsigned long asid, unsigned long page)
+void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid,
+ unsigned long page)
{
unsigned long addr, data;
@@ -91,7 +92,7 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page)
*/
addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
data = page | asid; /* VALID bit is off */
- jump_to_P2();
+ jump_to_uncached();
ctrl_outl(data, addr);
- back_to_P1();
+ back_to_cached();
}
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
new file mode 100644
index 000000000000..f34274a1ded3
--- /dev/null
+++ b/arch/sh/mm/tlb-sh5.c
@@ -0,0 +1,164 @@
+/*
+ * arch/sh/mm/tlb-sh5.c
+ *
+ * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2003 Richard Curnow <richard.curnow@superh.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+
+/**
+ * sh64_tlb_init
+ *
+ * Perform initial setup for the DTLB and ITLB.
+ */
+int __init sh64_tlb_init(void)
+{
+ /* Assign some sane DTLB defaults */
+ cpu_data->dtlb.entries = 64;
+ cpu_data->dtlb.step = 0x10;
+
+ cpu_data->dtlb.first = DTLB_FIXED | cpu_data->dtlb.step;
+ cpu_data->dtlb.next = cpu_data->dtlb.first;
+
+ cpu_data->dtlb.last = DTLB_FIXED |
+ ((cpu_data->dtlb.entries - 1) *
+ cpu_data->dtlb.step);
+
+ /* And again for the ITLB */
+ cpu_data->itlb.entries = 64;
+ cpu_data->itlb.step = 0x10;
+
+ cpu_data->itlb.first = ITLB_FIXED | cpu_data->itlb.step;
+ cpu_data->itlb.next = cpu_data->itlb.first;
+ cpu_data->itlb.last = ITLB_FIXED |
+ ((cpu_data->itlb.entries - 1) *
+ cpu_data->itlb.step);
+
+ return 0;
+}
+
+/**
+ * sh64_next_free_dtlb_entry
+ *
+ * Find the next available DTLB entry
+ */
+unsigned long long sh64_next_free_dtlb_entry(void)
+{
+ return cpu_data->dtlb.next;
+}
+
+/**
+ * sh64_get_wired_dtlb_entry
+ *
+ * Allocate a wired (locked-in) entry in the DTLB
+ */
+unsigned long long sh64_get_wired_dtlb_entry(void)
+{
+ unsigned long long entry = sh64_next_free_dtlb_entry();
+
+ cpu_data->dtlb.first += cpu_data->dtlb.step;
+ cpu_data->dtlb.next += cpu_data->dtlb.step;
+
+ return entry;
+}
+
+/**
+ * sh64_put_wired_dtlb_entry
+ *
+ * @entry: Address of TLB slot.
+ *
+ * Free a wired (locked-in) entry in the DTLB.
+ *
+ * Works like a stack, last one to allocate must be first one to free.
+ */
+int sh64_put_wired_dtlb_entry(unsigned long long entry)
+{
+ __flush_tlb_slot(entry);
+
+ /*
+ * We don't do any particularly useful tracking of wired entries,
+ * so this approach works like a stack .. last one to be allocated
+ * has to be the first one to be freed.
+ *
+ * We could potentially load wired entries into a list and work on
+ * rebalancing the list periodically (which also entails moving the
+ * contents of a TLB entry) .. though I have a feeling that this is
+ * more trouble than it's worth.
+ */
+
+ /*
+ * Entry must be valid .. we don't want any ITLB addresses!
+ */
+ if (entry <= DTLB_FIXED)
+ return -EINVAL;
+
+ /*
+ * Next, check if we're within range to be freed. (ie, must be the
+ * entry beneath the first 'free' entry!
+ */
+ if (entry < (cpu_data->dtlb.first - cpu_data->dtlb.step))
+ return -EINVAL;
+
+ /* If we are, then bring this entry back into the list */
+ cpu_data->dtlb.first -= cpu_data->dtlb.step;
+ cpu_data->dtlb.next = entry;
+
+ return 0;
+}
+
+/**
+ * sh64_setup_tlb_slot
+ *
+ * @config_addr: Address of TLB slot.
+ * @eaddr: Virtual address.
+ * @asid: Address Space Identifier.
+ * @paddr: Physical address.
+ *
+ * Load up a virtual<->physical translation for @eaddr<->@paddr in the
+ * pre-allocated TLB slot @config_addr (see sh64_get_wired_dtlb_entry).
+ */
+inline void sh64_setup_tlb_slot(unsigned long long config_addr,
+ unsigned long eaddr,
+ unsigned long asid,
+ unsigned long paddr)
+{
+ unsigned long long pteh, ptel;
+
+ /* Sign extension */
+#if (NEFF == 32)
+ pteh = (unsigned long long)(signed long long)(signed long) eaddr;
+#else
+#error "Can't sign extend more than 32 bits yet"
+#endif
+ pteh &= PAGE_MASK;
+ pteh |= (asid << PTEH_ASID_SHIFT) | PTEH_VALID;
+#if (NEFF == 32)
+ ptel = (unsigned long long)(signed long long)(signed long) paddr;
+#else
+#error "Can't sign extend more than 32 bits yet"
+#endif
+ ptel &= PAGE_MASK;
+ ptel |= (_PAGE_CACHABLE | _PAGE_READ | _PAGE_WRITE);
+
+ asm volatile("putcfg %0, 1, %1\n\t"
+ "putcfg %0, 0, %2\n"
+ : : "r" (config_addr), "r" (ptel), "r" (pteh));
+}
+
+/**
+ * sh64_teardown_tlb_slot
+ *
+ * @config_addr: Address of TLB slot.
+ *
+ * Teardown any existing mapping in the TLB slot @config_addr.
+ */
+inline void sh64_teardown_tlb_slot(unsigned long long config_addr)
+ __attribute__ ((alias("__flush_tlb_slot")));
diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlbflush_32.c
index 6f45c1f8a7fe..6f45c1f8a7fe 100644
--- a/arch/sh/mm/tlb-flush.c
+++ b/arch/sh/mm/tlbflush_32.c
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
new file mode 100644
index 000000000000..2a98c9ec88ff
--- /dev/null
+++ b/arch/sh/mm/tlbflush_64.c
@@ -0,0 +1,475 @@
+/*
+ * arch/sh/mm/tlb-flush_64.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes)
+ * Copyright (C) 2003 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/signal.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/tlb.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+extern void die(const char *,struct pt_regs *,long);
+
+#define PFLAG(val,flag) (( (val) & (flag) ) ? #flag : "" )
+#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
+
+static inline void print_prots(pgprot_t prot)
+{
+ printk("prot is 0x%08lx\n",pgprot_val(prot));
+
+ printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
+ PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
+}
+
+static inline void print_vma(struct vm_area_struct *vma)
+{
+ printk("vma start 0x%08lx\n", vma->vm_start);
+ printk("vma end 0x%08lx\n", vma->vm_end);
+
+ print_prots(vma->vm_page_prot);
+ printk("vm_flags 0x%08lx\n", vma->vm_flags);
+}
+
+static inline void print_task(struct task_struct *tsk)
+{
+ printk("Task pid %d\n", task_pid_nr(tsk));
+}
+
+static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
+{
+ pgd_t *dir;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+
+ dir = pgd_offset(mm, address);
+ if (pgd_none(*dir))
+ return NULL;
+
+ pud = pud_offset(dir, address);
+ if (pud_none(*pud))
+ return NULL;
+
+ pmd = pmd_offset(pud, address);
+ if (pmd_none(*pmd))
+ return NULL;
+
+ pte = pte_offset_kernel(pmd, address);
+ entry = *pte;
+ if (pte_none(entry) || !pte_present(entry))
+ return NULL;
+
+ return pte;
+}
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+ unsigned long textaccess, unsigned long address)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct * vma;
+ const struct exception_table_entry *fixup;
+ pte_t *pte;
+ int fault;
+
+ /* SIM
+ * Note this is now called with interrupts still disabled
+ * This is to cope with being called for a missing IO port
+ * address with interrupts disabled. This should be fixed as
+ * soon as we have a better 'fast path' miss handler.
+ *
+ * Plus take care how you try and debug this stuff.
+ * For example, writing debug data to a port which you
+ * have just faulted on is not going to work.
+ */
+
+ tsk = current;
+ mm = tsk->mm;
+
+ /* Not an IO address, so reenable interrupts */
+ local_irq_enable();
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_atomic() || !mm)
+ goto no_context;
+
+ /* TLB misses upon some cache flushes get done under cli() */
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, address);
+
+ if (!vma) {
+#ifdef DEBUG_FAULT
+ print_task(tsk);
+ printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+ __FUNCTION__,__LINE__,
+ address,regs->pc,textaccess,writeaccess);
+ show_regs(regs);
+#endif
+ goto bad_area;
+ }
+ if (vma->vm_start <= address) {
+ goto good_area;
+ }
+
+ if (!(vma->vm_flags & VM_GROWSDOWN)) {
+#ifdef DEBUG_FAULT
+ print_task(tsk);
+ printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+ __FUNCTION__,__LINE__,
+ address,regs->pc,textaccess,writeaccess);
+ show_regs(regs);
+
+ print_vma(vma);
+#endif
+ goto bad_area;
+ }
+ if (expand_stack(vma, address)) {
+#ifdef DEBUG_FAULT
+ print_task(tsk);
+ printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+ __FUNCTION__,__LINE__,
+ address,regs->pc,textaccess,writeaccess);
+ show_regs(regs);
+#endif
+ goto bad_area;
+ }
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (textaccess) {
+ if (!(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+ } else {
+ if (writeaccess) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & VM_READ))
+ goto bad_area;
+ }
+ }
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+survive:
+ fault = handle_mm_fault(mm, vma, address, writeaccess);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
+ /* If we get here, the page fault has been handled. Do the TLB refill
+ now from the newly-setup PTE, to avoid having to fault again right
+ away on the same instruction. */
+ pte = lookup_pte (mm, address);
+ if (!pte) {
+ /* From empirical evidence, we can get here, due to
+ !pte_present(pte). (e.g. if a swap-in occurs, and the page
+ is swapped back out again before the process that wanted it
+ gets rescheduled?) */
+ goto no_pte;
+ }
+
+ __do_tlb_refill(address, textaccess, pte);
+
+no_pte:
+
+ up_read(&mm->mmap_sem);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+#ifdef DEBUG_FAULT
+ printk("fault:bad area\n");
+#endif
+ up_read(&mm->mmap_sem);
+
+ if (user_mode(regs)) {
+ static int count=0;
+ siginfo_t info;
+ if (count < 4) {
+ /* This is really to help debug faults when starting
+ * usermode, so only need a few */
+ count++;
+ printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
+ address, task_pid_nr(current), current->comm,
+ (unsigned long) regs->pc);
+#if 0
+ show_regs(regs);
+#endif
+ }
+ if (is_global_init(tsk)) {
+ panic("INIT had user mode bad_area\n");
+ }
+ tsk->thread.address = address;
+ tsk->thread.error_code = writeaccess;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_addr = (void *) address;
+ force_sig_info(SIGSEGV, &info, tsk);
+ return;
+ }
+
+no_context:
+#ifdef DEBUG_FAULT
+ printk("fault:No context\n");
+#endif
+ /* Are we prepared to handle this kernel fault? */
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return;
+ }
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ *
+ */
+ if (address < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request");
+ printk(" at virtual address %08lx\n", address);
+ printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
+ die("Oops", regs, writeaccess);
+ do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ if (is_global_init(current)) {
+ panic("INIT out of memory\n");
+ yield();
+ goto survive;
+ }
+ printk("fault:Out of memory\n");
+ up_read(&mm->mmap_sem);
+ if (is_global_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ printk("VM: killing process %s\n", tsk->comm);
+ if (user_mode(regs))
+ do_group_exit(SIGKILL);
+ goto no_context;
+
+do_sigbus:
+ printk("fault:Do sigbus\n");
+ up_read(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.address = address;
+ tsk->thread.error_code = writeaccess;
+ tsk->thread.trap_no = 14;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+}
+
+void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address, pte_t pte)
+{
+ /*
+ * This appears to get called once for every pte entry that gets
+ * established => I don't think it's efficient to try refilling the
+ * TLBs with the pages - some may not get accessed even. Also, for
+ * executable pages, it is impossible to determine reliably here which
+ * TLB they should be mapped into (or both even).
+ *
+ * So, just do nothing here and handle faults on demand. In the
+ * TLBMISS handling case, the refill is now done anyway after the pte
+ * has been fixed up, so that deals with most useful cases.
+ */
+}
+
+void local_flush_tlb_one(unsigned long asid, unsigned long page)
+{
+ unsigned long long match, pteh=0, lpage;
+ unsigned long tlb;
+
+ /*
+ * Sign-extend based on neff.
+ */
+ lpage = (page & NEFF_SIGN) ? (page | NEFF_MASK) : page;
+ match = (asid << PTEH_ASID_SHIFT) | PTEH_VALID;
+ match |= lpage;
+
+ for_each_itlb_entry(tlb) {
+ asm volatile ("getcfg %1, 0, %0"
+ : "=r" (pteh)
+ : "r" (tlb) );
+
+ if (pteh == match) {
+ __flush_tlb_slot(tlb);
+ break;
+ }
+ }
+
+ for_each_dtlb_entry(tlb) {
+ asm volatile ("getcfg %1, 0, %0"
+ : "=r" (pteh)
+ : "r" (tlb) );
+
+ if (pteh == match) {
+ __flush_tlb_slot(tlb);
+ break;
+ }
+
+ }
+}
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ unsigned long flags;
+
+ if (vma->vm_mm) {
+ page &= PAGE_MASK;
+ local_irq_save(flags);
+ local_flush_tlb_one(get_asid(), page);
+ local_irq_restore(flags);
+ }
+}
+
+void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ unsigned long flags;
+ unsigned long long match, pteh=0, pteh_epn, pteh_low;
+ unsigned long tlb;
+ unsigned int cpu = smp_processor_id();
+ struct mm_struct *mm;
+
+ mm = vma->vm_mm;
+ if (cpu_context(cpu, mm) == NO_CONTEXT)
+ return;
+
+ local_irq_save(flags);
+
+ start &= PAGE_MASK;
+ end &= PAGE_MASK;
+
+ match = (cpu_asid(cpu, mm) << PTEH_ASID_SHIFT) | PTEH_VALID;
+
+ /* Flush ITLB */
+ for_each_itlb_entry(tlb) {
+ asm volatile ("getcfg %1, 0, %0"
+ : "=r" (pteh)
+ : "r" (tlb) );
+
+ pteh_epn = pteh & PAGE_MASK;
+ pteh_low = pteh & ~PAGE_MASK;
+
+ if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
+ __flush_tlb_slot(tlb);
+ }
+
+ /* Flush DTLB */
+ for_each_dtlb_entry(tlb) {
+ asm volatile ("getcfg %1, 0, %0"
+ : "=r" (pteh)
+ : "r" (tlb) );
+
+ pteh_epn = pteh & PAGE_MASK;
+ pteh_low = pteh & ~PAGE_MASK;
+
+ if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
+ __flush_tlb_slot(tlb);
+ }
+
+ local_irq_restore(flags);
+}
+
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+ unsigned long flags;
+ unsigned int cpu = smp_processor_id();
+
+ if (cpu_context(cpu, mm) == NO_CONTEXT)
+ return;
+
+ local_irq_save(flags);
+
+ cpu_context(cpu, mm) = NO_CONTEXT;
+ if (mm == current->mm)
+ activate_context(mm, cpu);
+
+ local_irq_restore(flags);
+}
+
+void local_flush_tlb_all(void)
+{
+ /* Invalidate all, including shared pages, excluding fixed TLBs */
+ unsigned long flags, tlb;
+
+ local_irq_save(flags);
+
+ /* Flush each ITLB entry */
+ for_each_itlb_entry(tlb)
+ __flush_tlb_slot(tlb);
+
+ /* Flush each DTLB entry */
+ for_each_dtlb_entry(tlb)
+ __flush_tlb_slot(tlb);
+
+ local_irq_restore(flags);
+}
+
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ /* FIXME: Optimize this later.. */
+ flush_tlb_all();
+}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index ff071693325c..25810670a0fa 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -29,7 +29,6 @@ HP6XX SH_HP6XX
DREAMCAST SH_DREAMCAST
MPC1211 SH_MPC1211
SNAPGEAR SH_SECUREEDGE5410
-HS7751RVOIP SH_HS7751RVOIP
EDOSK7705 SH_EDOSK7705
SH4202_MICRODEV SH_SH4202_MICRODEV
SH03 SH_SH03
@@ -45,3 +44,4 @@ X3PROTO SH_X3PROTO
MAGICPANELR2 SH_MAGIC_PANEL_R2
R2D_PLUS RTS7751R2D_PLUS
R2D_1 RTS7751R2D_1
+CAYMAN SH_CAYMAN