summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-07 16:18:05 -0800
committerGary King <gking@nvidia.com>2009-12-07 16:18:05 -0800
commitbb11d46b72a4a2b53f890faa970a380cf0084bf2 (patch)
tree2d9d2955e069fed69febbe567a835fcc48ec6ec6 /arch
parente1b5e49debba7174e7b9c48195de8abfd54911dd (diff)
parent74ece4056571443eef30d4dff62180944b5a39d8 (diff)
Merge commit 'arm/2.6.28-arm' into android-tegra-2.6.29
Conflicts: MAINTAINERS arch/arm/Kconfig arch/arm/Makefile arch/arm/boot/compressed/head.S arch/arm/common/Makefile arch/arm/configs/realview-smp_defconfig arch/arm/configs/realview_defconfig arch/arm/configs/versatile_defconfig arch/arm/include/asm/elf.h arch/arm/include/asm/uaccess.h arch/arm/kernel/module.c arch/arm/kernel/signal.c arch/arm/mach-realview/Kconfig arch/arm/mach-realview/Makefile arch/arm/mach-realview/core.c arch/arm/mach-realview/core.h arch/arm/mach-realview/include/mach/board-pba8.h arch/arm/mach-realview/include/mach/debug-macro.S arch/arm/mach-realview/include/mach/hardware.h arch/arm/mach-realview/include/mach/irqs.h arch/arm/mach-realview/include/mach/memory.h arch/arm/mach-realview/include/mach/uncompress.h arch/arm/mach-realview/localtimer.c arch/arm/mach-realview/platsmp.c arch/arm/mach-realview/realview_eb.c arch/arm/mach-realview/realview_pb1176.c arch/arm/mach-realview/realview_pb11mp.c arch/arm/mach-realview/realview_pba8.c arch/arm/mm/Kconfig arch/arm/mm/copypage-v6.c arch/arm/mm/dma-mapping.c arch/arm/mm/proc-v7.S arch/arm/oprofile/op_model_mpcore.c arch/arm/tools/mach-types arch/arm/vfp/vfpmodule.c drivers/mtd/maps/integrator-flash.c drivers/net/smsc911x.c drivers/net/smsc911x.h
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig193
-rw-r--r--arch/arm/Kconfig-nommu2
-rw-r--r--arch/arm/Kconfig.debug80
-rw-r--r--arch/arm/Makefile19
-rw-r--r--arch/arm/boot/Makefile9
-rw-r--r--arch/arm/boot/compressed/Makefile9
-rw-r--r--arch/arm/boot/compressed/head.S198
-rw-r--r--arch/arm/boot/compressed/misc.c194
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.in5
-rw-r--r--arch/arm/common/Kconfig3
-rw-r--r--arch/arm/common/Makefile3
-rw-r--r--arch/arm/common/nvic.c99
-rw-r--r--arch/arm/common/rvidcc_common.c794
-rw-r--r--arch/arm/common/rvidcc_config.h166
-rw-r--r--arch/arm/common/rvidcc_interface.h182
-rw-r--r--arch/arm/common/rvidcc_linux.c1014
-rw-r--r--arch/arm/configs/realview-nommu_defconfig1373
-rw-r--r--arch/arm/configs/realview_defconfig763
-rw-r--r--arch/arm/configs/versatile_defconfig2
-rw-r--r--arch/arm/include/asm/assembler.h95
-rw-r--r--arch/arm/include/asm/atomic.h56
-rw-r--r--arch/arm/include/asm/cacheflush.h40
-rw-r--r--arch/arm/include/asm/checksum.h1
-rw-r--r--arch/arm/include/asm/cputype.h27
-rw-r--r--arch/arm/include/asm/elf.h3
-rw-r--r--arch/arm/include/asm/futex.h1
-rw-r--r--arch/arm/include/asm/glue.h8
-rw-r--r--arch/arm/include/asm/hardware/cache-l2x0.h28
-rw-r--r--arch/arm/include/asm/hardware/debug-pl01x.S8
-rw-r--r--arch/arm/include/asm/irqflags.h41
-rw-r--r--arch/arm/include/asm/locks.h10
-rw-r--r--arch/arm/include/asm/memory.h5
-rw-r--r--arch/arm/include/asm/mmu.h1
-rw-r--r--arch/arm/include/asm/mmu_context.h17
-rw-r--r--arch/arm/include/asm/module.h22
-rw-r--r--arch/arm/include/asm/mutex.h3
-rw-r--r--arch/arm/include/asm/page-nommu.h3
-rw-r--r--arch/arm/include/asm/proc-fns.h8
-rw-r--r--arch/arm/include/asm/processor.h11
-rw-r--r--arch/arm/include/asm/ptrace.h63
-rw-r--r--arch/arm/include/asm/spinlock.h48
-rw-r--r--arch/arm/include/asm/stacktrace.h15
-rw-r--r--arch/arm/include/asm/system.h53
-rw-r--r--arch/arm/include/asm/thread_info.h2
-rw-r--r--arch/arm/include/asm/tlbflush.h119
-rw-r--r--arch/arm/include/asm/traps.h1
-rw-r--r--arch/arm/include/asm/uaccess.h12
-rw-r--r--arch/arm/include/asm/unified.h126
-rw-r--r--arch/arm/include/asm/unwind.h69
-rw-r--r--arch/arm/include/asm/vfpmacros.h5
-rw-r--r--arch/arm/kernel/Makefile10
-rw-r--r--arch/arm/kernel/armksyms.c4
-rw-r--r--arch/arm/kernel/asm-offsets.c4
-rw-r--r--arch/arm/kernel/debug.S3
-rw-r--r--arch/arm/kernel/early_printk.c38
-rw-r--r--arch/arm/kernel/elf.c9
-rw-r--r--arch/arm/kernel/entry-armv.S230
-rw-r--r--arch/arm/kernel/entry-common.S63
-rw-r--r--arch/arm/kernel/entry-header.S221
-rw-r--r--arch/arm/kernel/entry-v7m.S124
-rw-r--r--arch/arm/kernel/head-common.S26
-rw-r--r--arch/arm/kernel/head-nommu.S25
-rw-r--r--arch/arm/kernel/head.S31
-rw-r--r--arch/arm/kernel/module.c115
-rw-r--r--arch/arm/kernel/process.c46
-rw-r--r--arch/arm/kernel/ptrace.c8
-rw-r--r--arch/arm/kernel/setup.c53
-rw-r--r--arch/arm/kernel/signal.c10
-rw-r--r--arch/arm/kernel/smp.c147
-rw-r--r--arch/arm/kernel/stacktrace.c88
-rw-r--r--arch/arm/kernel/stacktrace.h9
-rw-r--r--arch/arm/kernel/time.c21
-rw-r--r--arch/arm/kernel/traps.c54
-rw-r--r--arch/arm/kernel/unwind.c437
-rw-r--r--arch/arm/kernel/vmlinux.lds.S27
-rw-r--r--arch/arm/lib/ashldi3.S5
-rw-r--r--arch/arm/lib/ashrdi3.S5
-rw-r--r--arch/arm/lib/backtrace.S16
-rw-r--r--arch/arm/lib/bitops.h24
-rw-r--r--arch/arm/lib/clear_user.S15
-rw-r--r--arch/arm/lib/copy_from_user.S22
-rw-r--r--arch/arm/lib/copy_page.S2
-rw-r--r--arch/arm/lib/copy_template.S25
-rw-r--r--arch/arm/lib/copy_to_user.S22
-rw-r--r--arch/arm/lib/csumpartial.S9
-rw-r--r--arch/arm/lib/csumpartialcopygeneric.S4
-rw-r--r--arch/arm/lib/csumpartialcopyuser.S49
-rw-r--r--arch/arm/lib/delay.S2
-rw-r--r--arch/arm/lib/div64.S14
-rw-r--r--arch/arm/lib/findbit.S34
-rw-r--r--arch/arm/lib/getuser.S5
-rw-r--r--arch/arm/lib/io-readsb.S8
-rw-r--r--arch/arm/lib/io-readsl.S6
-rw-r--r--arch/arm/lib/io-readsw-armv4.S6
-rw-r--r--arch/arm/lib/io-writesb.S8
-rw-r--r--arch/arm/lib/io-writesl.S5
-rw-r--r--arch/arm/lib/io-writesw-armv4.S13
-rw-r--r--arch/arm/lib/lib1funcs.S48
-rw-r--r--arch/arm/lib/lshrdi3.S5
-rw-r--r--arch/arm/lib/memchr.S3
-rw-r--r--arch/arm/lib/memcpy.S17
-rw-r--r--arch/arm/lib/memmove.S39
-rw-r--r--arch/arm/lib/memset.S10
-rw-r--r--arch/arm/lib/memzero.S10
-rw-r--r--arch/arm/lib/putuser.S15
-rw-r--r--arch/arm/lib/sha1.S2
-rw-r--r--arch/arm/lib/strchr.S2
-rw-r--r--arch/arm/lib/strncpy_from_user.S2
-rw-r--r--arch/arm/lib/strnlen_user.S2
-rw-r--r--arch/arm/lib/strrchr.S1
-rw-r--r--arch/arm/lib/testclearbit.S2
-rw-r--r--arch/arm/lib/testsetbit.S2
-rw-r--r--arch/arm/lib/ucmpdi2.S8
-rw-r--r--arch/arm/mach-integrator/include/mach/debug-macro.S1
-rw-r--r--arch/arm/mach-integrator/include/mach/entry-macro.S1
-rw-r--r--arch/arm/mach-integrator/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c16
-rw-r--r--arch/arm/mach-mps/Kconfig11
-rw-r--r--arch/arm/mach-mps/Makefile6
-rw-r--r--arch/arm/mach-mps/Makefile.boot3
-rw-r--r--arch/arm/mach-mps/board-mps.c191
-rw-r--r--arch/arm/mach-mps/clock.c131
-rw-r--r--arch/arm/mach-mps/clock.h25
-rw-r--r--arch/arm/mach-mps/core.c386
-rw-r--r--arch/arm/mach-mps/core.h69
-rw-r--r--arch/arm/mach-mps/include/mach/debug-macro.S24
-rw-r--r--arch/arm/mach-mps/include/mach/dma.h18
-rw-r--r--arch/arm/mach-mps/include/mach/entry-macro.S21
-rw-r--r--arch/arm/mach-mps/include/mach/hardware.h31
-rw-r--r--arch/arm/mach-mps/include/mach/io.h32
-rw-r--r--arch/arm/mach-mps/include/mach/irqs.h49
-rw-r--r--arch/arm/mach-mps/include/mach/memory.h34
-rw-r--r--arch/arm/mach-mps/include/mach/platform.h91
-rw-r--r--arch/arm/mach-mps/include/mach/system.h35
-rw-r--r--arch/arm/mach-mps/include/mach/timex.h20
-rw-r--r--arch/arm/mach-mps/include/mach/uncompress.h62
-rw-r--r--arch/arm/mach-mps/include/mach/vmalloc.h21
-rw-r--r--arch/arm/mach-realview/Kconfig30
-rw-r--r--arch/arm/mach-realview/Makefile1
-rw-r--r--arch/arm/mach-realview/core.c143
-rw-r--r--arch/arm/mach-realview/core.h7
-rw-r--r--arch/arm/mach-realview/include/mach/debug-macro.S29
-rw-r--r--arch/arm/mach-realview/include/mach/hardware.h9
-rw-r--r--arch/arm/mach-realview/include/mach/irqs.h1
-rw-r--r--arch/arm/mach-realview/include/mach/memory.h14
-rw-r--r--arch/arm/mach-realview/include/mach/uncompress.h3
-rw-r--r--arch/arm/mach-realview/localtimer.c48
-rw-r--r--arch/arm/mach-realview/platsmp.c38
-rw-r--r--arch/arm/mach-realview/realview_eb.c33
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c13
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c16
-rw-r--r--arch/arm/mach-versatile/core.c28
-rw-r--r--arch/arm/mm/Kconfig53
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/abort-ev6.S7
-rw-r--r--arch/arm/mm/abort-ev7m.S9
-rw-r--r--arch/arm/mm/alignment.c159
-rw-r--r--arch/arm/mm/cache-l2x0.c37
-rw-r--r--arch/arm/mm/cache-v6.S61
-rw-r--r--arch/arm/mm/cache-v7.S37
-rw-r--r--arch/arm/mm/context.c123
-rw-r--r--arch/arm/mm/copypage-v6.c1
-rw-r--r--arch/arm/mm/dma-mapping.c33
-rw-r--r--arch/arm/mm/fault-armv.c9
-rw-r--r--arch/arm/mm/fault.c22
-rw-r--r--arch/arm/mm/flush.c25
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm/mm/nommu.c3
-rw-r--r--arch/arm/mm/proc-macros.S2
-rw-r--r--arch/arm/mm/proc-v6.S19
-rw-r--r--arch/arm/mm/proc-v7.S62
-rw-r--r--arch/arm/mm/proc-v7m.S184
-rw-r--r--arch/arm/mm/tlb-v7.S17
-rw-r--r--arch/arm/oprofile/Makefile8
-rw-r--r--arch/arm/oprofile/backtrace.c14
-rw-r--r--arch/arm/oprofile/common.c43
-rw-r--r--arch/arm/oprofile/op_arm11.c164
-rw-r--r--arch/arm/oprofile/op_arm11.h44
-rw-r--r--arch/arm/oprofile/op_arm_model.h89
-rw-r--r--arch/arm/oprofile/op_counter.h27
-rw-r--r--arch/arm/oprofile/op_l2x0.c244
-rw-r--r--arch/arm/oprofile/op_l2x0.h15
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.c162
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.h45
-rw-r--r--arch/arm/oprofile/op_model_mpcore.h61
-rw-r--r--arch/arm/oprofile/op_model_v6-7.c243
-rw-r--r--arch/arm/oprofile/op_model_v6.c67
-rw-r--r--arch/arm/oprofile/op_model_v7.c411
-rw-r--r--arch/arm/oprofile/op_model_v7.h103
-rw-r--r--arch/arm/oprofile/op_scu.c175
-rw-r--r--arch/arm/oprofile/op_scu.h23
-rw-r--r--arch/arm/oprofile/op_v7.c248
-rw-r--r--arch/arm/oprofile/op_v7.h36
-rw-r--r--arch/arm/tools/gen-mach-types6
-rw-r--r--arch/arm/tools/mach-types1
-rw-r--r--arch/arm/vfp/entry.S2
-rw-r--r--arch/arm/vfp/vfp.h1
-rw-r--r--arch/arm/vfp/vfphw.S48
-rw-r--r--arch/arm/vfp/vfpmodule.c25
199 files changed, 10825 insertions, 2321 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 827196339893..b85246ee78da 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -49,10 +49,6 @@ config GENERIC_CLOCKEVENTS_BROADCAST
depends on GENERIC_CLOCKEVENTS
default y if SMP && !LOCAL_TIMERS
-config MMU
- bool
- default y
-
config NO_IOPORT
bool
default n
@@ -194,6 +190,13 @@ source "kernel/Kconfig.freezer"
menu "System Type"
+config MMU
+ bool "MMU-based Paged Memory Management Support"
+ default y
+ help
+ Select if you want MMU-based virtualised addressing space
+ support by paged memory management. If unsure, say 'Y'.
+
choice
prompt "ARM system type"
default ARCH_VERSATILE
@@ -590,6 +593,19 @@ config ARCH_W90X900
Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
can login www.mcuos.com or www.nuvoton.com to know more.
+config ARCH_MPS
+ bool "ARM Ltd. Microcontroller Prototyping System"
+ depends on !MMU
+ select ARM_AMBA
+ select HAVE_CLK
+ select COMMON_CLKDEV
+ select ICST307
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ help
+ This enables support for ARM Ltd. Microcontroller Prototyping
+ System platform.
+
endchoice
source "arch/arm/mach-clps711x/Kconfig"
@@ -676,6 +692,8 @@ source "arch/arm/mach-msm/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
+source "arch/arm/mach-mps/Kconfig"
+
# Definitions to make life easier
config ARCH_ACORN
bool
@@ -706,6 +724,105 @@ if !MMU
source "arch/arm/Kconfig-nommu"
endif
+config ARM_ERRATA_364296
+ bool "Enable partial low interrupt latency mode for ARM1136"
+ depends on CPU_V6 && !SMP
+ default n
+ help
+ This options enables the workaround for the 364296 ARM1136
+ r0pX errata (possible cache data corruption with
+ hit-under-miss enabled). It sets the undocumented bit 31 in
+ the auxiliary control register and the FI bit in the control
+ register, thus disabling hit-under-miss without putting the
+ processor into full low interrupt latency mode. ARM11MPCore
+ is not affected.
+
+config ARM_ERRATA_411920
+ bool "Workaround for the global I cache invalidation on ARM1136"
+ depends on CPU_V6 && !SMP
+ default n
+ help
+ Invalidation of the Instruction Cache operation can
+ fail. This Erratum is present in 1136, 1156 and 1176. It
+ does not affect the MPCore. This option enables the ARM Ltd.
+ recommended workaround.
+
+config ARM_ERRATA_351422
+ bool "Spinlocks using LDREX and STREX instructions can livelock"
+ depends on CPU_V6 && SMP
+ default n
+ help
+ According to the ARM11MPCore Erratum 351422 (r0p0), under
+ extremely rare conditions, in an MPCore node consisting of
+ at least 3 CPUs, two CPUs trying to perform a STREX to data
+ on the same shared cache line can enter a livelock
+ situation. This option adds variable spinning time to the
+ locking routines.
+
+config ARM_ERRATA_430973
+ bool "Stale prediction on replaced interworking branch on Cortex-A8"
+ depends on CPU_V7
+ default n
+ help
+ This option enables the workaround for the 430973 Cortex-A8
+ (r1p0) erratum. If a code sequence containing an ARM/Thumb
+ interworking branch is replaced with another code sequence
+ at the same virtual address, whether due to self-modifying
+ code or virtual to physical address re-mapping, Cortex-A8
+ does not recover from the stale interworking branch
+ prediction. This results in Cortex-A8 executing the new code
+ sequence in the incorrect ARM or Thumb state.
+
+config ARM_ERRATA_458693
+ bool "Processor deadlock when a false hazard is created on Cortex-A8"
+ depends on CPU_V7
+ default n
+ help
+ This option enables the workaround for the 458693 Cortex-A8
+ (r2p0) erratum. For very specific sequences of memory
+ operations, it is possible for a hazard condition intended
+ for a cache line to instead be incorrectly associated with a
+ different cache line. This false hazard might then cause a
+ processor deadlock.
+
+config ARM_ERRATA_460075
+ bool "Data written to the L2 cache can be overwritten with stale data on Cortex-A8"
+ depends on CPU_V7
+ default n
+ help
+ This option enables the workaround for the 458692 Cortex-A8
+ (r2p0) erratum. Any asynchronous access to the L2 cache may
+ encounter a situation in which recent store transactions to
+ the L2 cache are lost and overwritten with stale memory
+ contents from external memory.
+
+config ARM_ERRATUM_451034
+ bool "Enable workaround for ARM erratum 451034"
+ depends on VFPv3
+ help
+ On Cortex-A8 r1p0 and r1p1, executing a NEON store with an integer
+ store in the store buffer, can cause a processor deadlock under
+ certain conditions.
+
+ See ARM Cortex-A8 Errata Notice (PR120-PRDC-008070) for full details.
+
+ Say Y to include a partial workaround.
+
+ WARNING: Even with this option enabled, userspace code can trigger
+ the deadlock. To safely run untrusted code, a different fix is
+ required.
+
+config ARM_ERRATA_484863
+ bool "The Cache Sync operation does not guarantee that the the Eviction Buffer is empty"
+ depends on CACHE_L2X0
+ default n
+ help
+ According to the L220 Erratum 484863, the actual behaviour of
+ the L220 cache controller is that the Cache Sync operation
+ only ensures that the Write Buffer and the Write Allocate
+ Buffer are empty but not the Eviction Buffer. This option
+ enables the first workaround from the Errata document.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -773,7 +890,7 @@ source "kernel/time/Kconfig"
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
- depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+ depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX)
select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
@@ -830,7 +947,7 @@ config HOTPLUG_CPU
config LOCAL_TIMERS
bool "Use local timer interrupts"
- depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)
+ depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP || MACH_REALVIEW_PBX)
default y
help
Enable support for local timers on SMP platforms, rather then the
@@ -859,6 +976,23 @@ config HZ
default AT91_TIMER_HZ if ARCH_AT91
default 100
+config THUMB2_KERNEL
+ bool "Compile the kernel in Thumb-2 mode"
+ depends on (CPU_V7 || CPU_V7M) && EXPERIMENTAL
+ default n
+ select AEABI
+ select ARM_ASM_UNIFIED
+ help
+ By enabling this option, the kernel will be compiled in
+ Thumb-2 mode. A compiler/assembler that understand the unified
+ ARM-Thumb syntax is needed.
+
+ If unsure, say N.
+
+config ARM_ASM_UNIFIED
+ bool
+ default n
+
config AEABI
bool "Use the ARM EABI to compile the kernel"
help
@@ -876,7 +1010,7 @@ config AEABI
config OABI_COMPAT
bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"
- depends on AEABI && EXPERIMENTAL
+ depends on AEABI && !CPU_V7M && EXPERIMENTAL
default y
help
This option preserves the old syscall interface along with the
@@ -925,7 +1059,7 @@ config LEDS
ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
ARCH_AT91 || ARCH_DAVINCI || \
- ARCH_KS8695 || MACH_RD88F5182
+ ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
help
If you say Y here, the LEDs on your machine will be used
to provide useful information about your current system status.
@@ -1082,11 +1216,43 @@ config ATAGS_PROC
Should the atags used to boot the kernel be exported in an "atags"
file in procfs. Useful with kexec.
+config NAKED_BOOT
+ bool "Kernel image for naked booting environments"
+ depends on CMDLINE != ""
+ default n
+ help
+ This produces a kernel binary that can simply be moved onto
+ the target machine and jumped to without any sort of boot
+ protocol from the bootloader. This should only be used in
+ cases where the bootloader fails to implement the required
+ calling convention for executing the kernel as described in
+ the file Documentation/arm/Booting.
+
+ The use of this option imposes many restrictions on the kernel
+ as it may not support more than one target machine, and all
+ boot parameters such as memory size and root filesystem device
+ have to be hardcoded in the default kernel command string (see
+ CONFIG_CMDLINE).
+
+ If dynamic ram configuration, multi-machine support or the
+ ability for the user to specify a kernel command string at
+ boot without the need for recompiling the kernel each time
+ is required, then the bootloader must implement the boot
+ protocol as described in Documentation/arm/Booting and this
+ config option not be used.
+
+ Please consider fixing your bootloader according to the
+ documented boot protocol in all cases, or choose one
+ from the many excellent open source bootloaders available
+ on the net which already support the required boot protocol.
+
+ If you're not sure what this is all about then say N.
+
endmenu
menu "CPU Power Management"
-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA || ARCH_REALVIEW)
source "drivers/cpufreq/Kconfig"
@@ -1126,6 +1292,15 @@ config CPU_FREQ_PXA
default y
select CPU_FREQ_DEFAULT_GOV_USERSPACE
+config CPU_FREQ_REALVIEW
+ tristate "CPUfreq driver for ARM RealView platform"
+ depends on CPU_FREQ && MACH_REALVIEW_PB1176
+ default y
+ help
+ This enables the CPUfreq driver for ARM RealView platform.
+
+ If in doubt, say Y.
+
endif
source "drivers/cpuidle/Kconfig"
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 901e6dff8437..90521b3fa5e3 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -28,7 +28,7 @@ config FLASH_SIZE
config PROCESSOR_ID
hex 'Hard wire the processor ID'
default 0x00007700
- depends on !CPU_CP15
+ depends on !(CPU_CP15 || CPU_V7M)
help
If processor has no CP15 register, this processor ID is
used instead of the auto-probing which utilizes the register.
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 192ee01a9ba2..f34b02fa20cc 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,18 +2,29 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-# RMK wants arm kernels compiled with frame pointers so hardwire this to y.
+# RMK wants arm kernels compiled with frame pointers or stack unwinding.
# If you know what you are doing and are willing to live without stack
# traces, you can get a slightly smaller kernel by setting this option to
# n, but then RMK will have to kill you ;).
config FRAME_POINTER
bool
- default y
+ default y if !ARM_UNWIND && !THUMB2_KERNEL
help
If you say N here, the resulting kernel will be slightly smaller and
- faster. However, when a problem occurs with the kernel, the
- information that is reported is severely limited. Most people
- should say Y here.
+ faster. However, if neither FRAME_POINTER nor ARM_UNWIND are enabled,
+ when a problem occurs with the kernel, the information that is
+ reported is severely limited.
+
+config ARM_UNWIND
+ bool "Enable stack unwinding support"
+ depends on AEABI && EXPERIMENTAL
+ default y
+ help
+ This option enables stack unwinding support in the kernel
+ using the information automatically generated by the
+ compiler. The resulting kernel image is slightly bigger but
+ the performance is not affected. Currently, this feature
+ only works with EABI compilers. If unsure say Y.
config DEBUG_USER
bool "Verbose user fault messages"
@@ -50,6 +61,57 @@ config DEBUG_STACK_USAGE
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T output.
+config DEBUG_RVIDCC
+ bool "Include the RealView ICE DCC channel device driver"
+ depends on !DEBUG_ICEDCC
+ help
+ Say Y here if you want a serial channel connected through ARM's
+ RealView ICE emulator through to your debugging host.
+
+ IMPORTANT: if you are not using one of the pre-configured platforms
+ (notably ARM's Integrator or Versatile Platform) then you will need to
+ configure interrupts for DCC and pass the IRQ numbers in the module
+ parameters 'txirq' and 'rxirq', assuming they have been wired into your
+ interrupt controller.
+
+ If interrupts are not used then a timed polling scheme is used. This
+ introduces poorer performance, using more CPU bandwidth and reducing
+ communication throughput on DCC.
+
+ This feature requires at least the RealView ICE 1.5 firmware version.
+
+config DEBUG_DCC_KGDB
+ bool "Use the RealView ICE DCC serial channel for KGDB debugging"
+ depends on DEBUG_RVIDCC && KGDB
+ help
+ Say Y here if you want to remotely debug the kernel using gdb and the
+ KGDB kernel debugging patches. Refer to the KGDB documentation for more
+ details.
+
+ Note that only one device can be enabled as the KGDB communications
+ device, so if this is selected, then KGDB on serial devices or Ethernet
+ must be deselected, or the kernel won't link.
+
+config DEBUG_DCC_RAW
+ bool "Disable virtual Ethernet on the RealView ICE DCC channel"
+ depends on DEBUG_RVIDCC
+ help
+ Say Y here if you want to disable the virtual Ethernet facility
+ of the RealView ICE.
+
+ The virtual Ethernet facility provides both a serial channel and an
+ Ethernet channel, and can be used for its serial channel even if
+ Ethernet is not required. Using this has the advantage over raw
+ DCC communications in that serial channel writes that do not have
+ an integral multiple of 4 bytes are not stuffed with nulls to make
+ the packet size.
+
+ DCC communicates in 32-bit words and, in raw mode, data is packed in
+ 4 bytes per word. Individual write calls pack the data provided, padding
+ any remainder with nulls. Any protocol using this channel must tolerate
+ the embedded nulls. GDB is such a protocol, provided the driver is fed with
+ complete packets, and not one byte at a time.
+
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions"
@@ -59,6 +121,14 @@ config DEBUG_LL
in the kernel. This is helpful if you are debugging code that
executes before the console is initialized.
+config DEBUG_LL_CONSOLE
+ bool "Kernel early console"
+ depends on DEBUG_LL
+ help
+ Say Y here if you want to have an early console using the Kernel
+ low-level debugging functions. Add earlyprintk to your kernel
+ parameters to enable this console.
+
config DEBUG_ICEDCC
bool "Kernel low-level debugging via EmbeddedICE DCC channel"
depends on DEBUG_LL
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 24e0f0187697..9810f6885bff 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -11,6 +11,9 @@
# Copyright (C) 1995-2001 by Russell King
LDFLAGS_vmlinux :=-p --no-undefined -X
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux += --be8
+endif
CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
GZFLAGS :=-9
@@ -47,6 +50,7 @@ comma = ,
# Note that GCC does not numerically define an architecture version
# macro, but instead defines a whole series of macros which makes
# testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M) :=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
arch-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
# Only override the compiler option if ARMv6. The ARMv6K extensions are
@@ -85,9 +89,19 @@ else
CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
endif
+ifeq ($(CONFIG_ARM_UNWIND),y)
+CFLAGS_ABI +=-funwind-tables
+endif
+
+ifeq ($(CONFIG_THUMB2_KERNEL),y)
+AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W)
+CFLAGS_THUMB2 :=-mthumb $(AFLAGS_NOWARN)
+AFLAGS_THUMB2 :=$(CFLAGS_THUMB2) -Wa$(comma)-mthumb
+endif
+
# Need -Uarm for gcc < 3.x
-KBUILD_CFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
-KBUILD_AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float
+KBUILD_CFLAGS +=$(CFLAGS_ABI) $(CFLAGS_THUMB2) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
+KBUILD_AFLAGS +=$(CFLAGS_ABI) $(AFLAGS_THUMB2) $(arch-y) $(tune-y) -include asm/unified.h -msoft-float
CHECKFLAGS += -D__arm__
@@ -149,6 +163,7 @@ endif
machine-$(CONFIG_ARCH_LOKI) := loki
machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0
machine-$(CONFIG_ARCH_W90X900) := w90x900
+ machine-$(CONFIG_ARCH_MPS) := mps
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index da226abce2d0..b2b146d39cec 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -61,7 +61,7 @@ endif
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
- -C none -a $(LOADADDR) -e $(LOADADDR) \
+ -C none -a $(LOADADDR) -e $(STARTADDR) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
ifeq ($(CONFIG_ZBOOT_ROM),y)
@@ -70,6 +70,13 @@ else
$(obj)/uImage: LOADADDR=$(ZRELADDR)
endif
+ifeq ($(CONFIG_THUMB2_KERNEL),y)
+# Set bit 0 to 1 so that "mov pc, lr" switches to Thumb-2 mode
+$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/")
+else
+$(obj)/uImage: STARTADDR=$(LOADADDR)
+endif
+
$(obj)/uImage: $(obj)/zImage FORCE
$(call if_changed,uimage)
@echo ' Image $@ is ready'
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index fbe5eef1f6c9..0234bf9bb1fc 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -40,7 +40,7 @@ ifeq ($(CONFIG_PXA_SHARPSL),y)
OBJS += head-sharpsl.o
endif
-ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ifeq ($(CONFIG_CPU_ENDIAN_BE32),y)
ifeq ($(CONFIG_CPU_CP15),y)
OBJS += big-endian.o
else
@@ -57,7 +57,7 @@ ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
-ZTEXTADDR := 0
+ZTEXTADDR := $(ZRELADDR)
ZBSSADDR := ALIGN(4)
endif
@@ -72,12 +72,17 @@ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
endif
EXTRA_CFLAGS := -fpic -fno-builtin
+ifneq ($(CONFIG_CPU_V7M),y)
EXTRA_AFLAGS := -Wa,-march=all
+endif
# Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
# linker symbols. We only define initrd_phys and params_phys if the
# machine class defined the corresponding makefile variable.
LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux += --be8
+endif
ifneq ($(INITRD_PHYS),)
LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
endif
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 77d614232d81..52954f91ee98 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -117,6 +117,12 @@ start:
mov r0, r0
.endr
+#ifdef CONFIG_NAKED_BOOT
+#include <mach/debug-macro.S>
+ addruart r7
+ inituart r8, r7
+#endif
+
b 1f
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
@@ -124,6 +130,7 @@ start:
1: mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
+#ifndef CONFIG_CPU_V7M
#ifndef __ARM_ARCH_2__
/*
* Booting from Angel - need to enter SVC mode and disable
@@ -134,7 +141,8 @@ start:
tst r2, #3 @ not user?
bne not_angel
mov r0, #0x17 @ angel_SWIreason_EnterSVC
- swi 0x123456 @ angel_SWI_ARM
+ ARM( swi 0x123456 ) @ angel_SWI_ARM
+ THUMB( svc 0xab ) @ angel_SWI_THUMB
not_angel:
mrs r2, cpsr @ turn off interrupts to
orr r2, r2, #0xc0 @ prevent angel from running
@@ -142,6 +150,7 @@ not_angel:
#else
teqp pc, #0x0c000003 @ turn off interrupts
#endif
+#endif
/*
* Note that some cache flushing and other stuff may
@@ -155,7 +164,9 @@ not_angel:
.text
adr r0, LC0
- ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
+ ARM( ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} )
+ THUMB( ldmia r0, {r1, r2, r3, r4, r5, r6, ip} )
+ THUMB( ldr sp, [r0, #28] )
subs r0, r0, r1 @ calculate the delta offset
@ if delta is zero, we are
@@ -257,22 +268,25 @@ not_relocated: mov r0, #0
* r6 = processor ID
* r7 = architecture ID
* r8 = atags pointer
- * r9-r14 = corrupted
+ * r9-r12,r14 = corrupted
*/
add r1, r5, r0 @ end of decompressed kernel
adr r2, reloc_start
ldr r3, LC1
add r3, r2, r3
-1: ldmia r2!, {r9 - r14} @ copy relocation code
- stmia r1!, {r9 - r14}
- ldmia r2!, {r9 - r14}
- stmia r1!, {r9 - r14}
+1: ldmia r2!, {r9 - r12, r14} @ copy relocation code
+ stmia r1!, {r9 - r12, r14}
+ ldmia r2!, {r9 - r12, r14}
+ stmia r1!, {r9 - r12, r14}
cmp r2, r3
blo 1b
- add sp, r1, #128 @ relocate the stack
+ mov sp, r1
+ add sp, sp, #128 @ relocate the stack
bl cache_clean_flush
- add pc, r5, r0 @ call relocation code
+ ARM( add pc, r5, r0 ) @ call relocation code
+ THUMB( add r12, r5, r0 )
+ THUMB( mov pc, r12 ) @ call relocation code
/*
* We're not in danger of overwriting ourselves. Do this the simple way.
@@ -285,6 +299,7 @@ wont_overwrite: mov r0, r4
bl decompress_kernel
b call_kernel
+ .align 2
.type LC0, #object
LC0: .word LC0 @ r1
.word __bss_start @ r2
@@ -399,8 +414,10 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size
orr r1, r1, #3 << 10
add r2, r3, #16384
1: cmp r1, r9 @ if virt > start of RAM
+ it hs
orrhs r1, r1, #0x0c @ set cacheable, bufferable
cmp r1, r10 @ if virt > end of RAM
+ it hs
bichs r1, r1, #0x0c @ clear cacheable, bufferable
str r1, [r0], #4 @ 1:1 mapping
add r1, r1, #1048576
@@ -425,6 +442,7 @@ ENDPROC(__setup_mmu)
__armv4_mmu_cache_on:
mov r12, lr
+#ifdef CONFIG_MMU
bl __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
@@ -432,27 +450,41 @@ __armv4_mmu_cache_on:
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x0030
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ orr r0, r0, #1 << 25 @ big-endian page tables
+#endif
bl __common_mmu_cache_on
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
+#endif
mov pc, r12
__armv7_mmu_cache_on:
mov r12, lr
+#ifdef CONFIG_MMU
mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0
tst r11, #0xf @ VMSA
+ it ne
blne __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
tst r11, #0xf @ VMSA
+ it ne
mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
+#endif
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x003c @ write buffer
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ orr r0, r0, #1 << 25 @ big-endian page tables
+#endif
+#ifdef CONFIG_MMU
+ itttt ne
orrne r0, r0, #1 @ MMU enabled
movne r1, #-1
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
+#endif
mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back
mov r0, #0
@@ -472,6 +504,7 @@ __arm6_mmu_cache_on:
mov pc, r12
__common_mmu_cache_on:
+#ifndef CONFIG_THUMB2_KERNEL
#ifndef DEBUG
orr r0, r0, #0x000d @ Write buffer, mmu
#endif
@@ -483,6 +516,7 @@ __common_mmu_cache_on:
1: mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back to
sub pc, lr, r0, lsr #32 @ properly flush pipeline
+#endif
/*
* All code following this line is relocatable. It is relocated by
@@ -496,7 +530,7 @@ __common_mmu_cache_on:
* r6 = processor ID
* r7 = architecture ID
* r8 = atags pointer
- * r9-r14 = corrupted
+ * r9-r12,r14 = corrupted
*/
.align 5
reloc_start: add r9, r5, r0
@@ -505,13 +539,14 @@ reloc_start: add r9, r5, r0
mov r1, r4
1:
.rept 4
- ldmia r5!, {r0, r2, r3, r10 - r14} @ relocate kernel
- stmia r1!, {r0, r2, r3, r10 - r14}
+ ldmia r5!, {r0, r2, r3, r10 - r12, r14} @ relocate kernel
+ stmia r1!, {r0, r2, r3, r10 - r12, r14}
.endr
cmp r5, r9
blo 1b
- add sp, r1, #128 @ relocate the stack
+ mov sp, r1
+ add sp, sp, #128 @ relocate the stack
debug_reloc_end
call_kernel: bl cache_clean_flush
@@ -535,17 +570,24 @@ call_kernel: bl cache_clean_flush
* r12 = corrupted
*/
-call_cache_fn: adr r12, proc_types
+call_cache_fn:
+ adr r12, proc_types
#ifdef CONFIG_CPU_CP15
mrc p15, 0, r6, c0, c0 @ get processor ID
+#elif defined(CONFIG_CPU_V7M)
+ ldr r6, =0xe000ed00 @ CPUID register address
+ ldr r6, [r6]
#else
ldr r6, =CONFIG_PROCESSOR_ID
#endif
-1: ldr r1, [r12, #0] @ get value
- ldr r2, [r12, #4] @ get mask
- eor r1, r1, r6 @ (real ^ match)
- tst r1, r2 @ & mask
- addeq pc, r12, r3 @ call cache function
+1: ldr r2, [r12, #4] @ get mask
+ ldr r1, [r12, #0] @ get value
+ and r2, r6, r2 @ keep the relevant bits
+ teq r1, r2 @ match with the value
+ itt eq
+ ARM( addeq pc, r12, r3 ) @ call cache function
+ THUMB( addeq r12, r3 )
+ THUMB( moveq pc, r12 ) @ call cache function
add r12, r12, #4*5
b 1b
@@ -563,13 +605,15 @@ call_cache_fn: adr r12, proc_types
* methods. Writeback caches _must_ have the flush method
* defined.
*/
+ .align 2
.type proc_types,#object
proc_types:
.word 0x41560600 @ ARM6/610
.word 0xffffffe0
- b __arm6_mmu_cache_off @ works, but slow
- b __arm6_mmu_cache_off
+ W(b) __arm6_mmu_cache_off @ works, but slow
+ W(b) __arm6_mmu_cache_off
mov pc, lr
+ THUMB( nop )
@ b __arm6_mmu_cache_on @ untested
@ b __arm6_mmu_cache_off
@ b __armv3_mmu_cache_flush
@@ -577,52 +621,60 @@ proc_types:
.word 0x00000000 @ old ARM ID
.word 0x0000f000
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
.word 0x41007000 @ ARM7/710
.word 0xfff8fe00
- b __arm7_mmu_cache_off
- b __arm7_mmu_cache_off
+ W(b) __arm7_mmu_cache_off
+ W(b) __arm7_mmu_cache_off
mov pc, lr
+ THUMB( nop )
.word 0x41807200 @ ARM720T (writethrough)
.word 0xffffff00
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
mov pc, lr
+ THUMB( nop )
.word 0x41007400 @ ARM74x
.word 0xff00ff00
- b __armv3_mpu_cache_on
- b __armv3_mpu_cache_off
- b __armv3_mpu_cache_flush
+ W(b) __armv3_mpu_cache_on
+ W(b) __armv3_mpu_cache_off
+ W(b) __armv3_mpu_cache_flush
.word 0x41009400 @ ARM94x
.word 0xff00ff00
- b __armv4_mpu_cache_on
- b __armv4_mpu_cache_off
- b __armv4_mpu_cache_flush
+ W(b) __armv4_mpu_cache_on
+ W(b) __armv4_mpu_cache_off
+ W(b) __armv4_mpu_cache_flush
.word 0x00007000 @ ARM7 IDs
.word 0x0000f000
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
@ Everything from here on will be the new ID system.
.word 0x4401a100 @ sa110 / sa1100
.word 0xffffffe0
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x6901b110 @ sa1110
.word 0xfffffff0
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x56056930
.word 0xff0ffff0 @ PXA935
@@ -632,47 +684,52 @@ proc_types:
.word 0x56050000 @ Feroceon
.word 0xff0f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv5tej_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv5tej_mmu_cache_flush
@ These match on the architecture ID
.word 0x00020000 @ ARMv4T
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x00050000 @ ARMv5TE
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x00060000 @ ARMv5TEJ
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv5tej_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x0007b000 @ ARMv6
.word 0x000ff000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv6_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv6_mmu_cache_flush
+#ifndef CONFIG_CPU_V7M
.word 0x000f0000 @ new CPU Id
.word 0x000f0000
- b __armv7_mmu_cache_on
- b __armv7_mmu_cache_off
- b __armv7_mmu_cache_flush
+ W(b) __armv7_mmu_cache_on
+ W(b) __armv7_mmu_cache_off
+ W(b) __armv7_mmu_cache_flush
+#endif
.word 0 @ unrecognised type
.word 0
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
.size proc_types, . - proc_types
@@ -707,22 +764,30 @@ __armv3_mpu_cache_off:
mov pc, lr
__armv4_mmu_cache_off:
+#ifdef CONFIG_MMU
mrc p15, 0, r0, c1, c0
bic r0, r0, #0x000d
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4
mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
+#endif
mov pc, lr
__armv7_mmu_cache_off:
mrc p15, 0, r0, c1, c0
+#ifdef CONFIG_MMU
bic r0, r0, #0x000d
+#else
+ bic r0, r0, #0x000c
+#endif
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
mov r12, lr
bl __armv7_mmu_cache_flush
mov r0, #0
+#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB
+#endif
mcr p15, 0, r0, c7, c5, 6 @ invalidate BTC
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
@@ -771,6 +836,7 @@ __armv4_mpu_cache_flush:
bcs 1b @ segments 7 to 0
teq r2, #0
+ it ne
mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
@@ -793,7 +859,7 @@ __armv7_mmu_cache_flush:
b iflush
hierarchical:
mcr p15, 0, r10, c7, c10, 5 @ DMB
- stmfd sp!, {r0-r5, r7, r9, r11}
+ stmfd sp!, {r0-r7, r9-r11}
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
@@ -818,8 +884,12 @@ loop1:
loop2:
mov r9, r4 @ create working copy of max way size
loop3:
- orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
- orr r11, r11, r7, lsl r2 @ factor index number into r11
+ ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
+ ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11
+ THUMB( lsl r6, r9, r5 )
+ THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
+ THUMB( lsl r6, r7, r2 )
+ THUMB( orr r11, r11, r6 ) @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge loop3
@@ -830,7 +900,7 @@ skip:
cmp r3, r10
bgt loop1
finished:
- ldmfd sp!, {r0-r5, r7, r9, r11}
+ ldmfd sp!, {r0-r7, r9-r11}
mov r10, #0 @ swith back to cache level 0
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
iflush:
@@ -858,15 +928,20 @@ __armv4_mmu_cache_flush:
mov r2, #1024
mov r2, r2, lsl r1 @ base dcache size *2
tst r3, #1 << 14 @ test M bit
+ it ne
addne r2, r2, r2, lsr #1 @ +1/2 size if M == 1
mov r3, r3, lsr #12
and r3, r3, #3
mov r11, #8
mov r11, r11, lsl r3 @ cache line size in bytes
no_cache_id:
- bic r1, pc, #63 @ align to longest cache line
+ mov r1, pc
+ bic r1, r1, #63 @ align to longest cache line
add r2, r1, r2
-1: ldr r3, [r1], r11 @ s/w flush D cache
+1:
+ ARM( ldr r3, [r1], r11 ) @ s/w flush D cache
+ THUMB( ldr r3, [r1] ) @ s/w flush D cache
+ THUMB( add r1, r1, r11 )
teq r1, r2
bne 1b
@@ -886,6 +961,7 @@ __armv3_mpu_cache_flush:
* memory, which again must be relocatable.
*/
#ifdef DEBUG
+ .align 2
.type phexbuf,#object
phexbuf: .space 12
.size phexbuf, . - phexbuf
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 3fc08413fff0..0dd03b6e6b1c 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -19,56 +19,14 @@
unsigned int __machine_arch_type;
#include <linux/string.h>
+#include <mach/uncompress.h>
#ifdef STANDALONE_DEBUG
#define putstr printf
+#elif defined(CONFIG_DEBUG_ICEDCC) || defined(CONFIG_DEBUG_RVIDCC)
+#define putstr icedcc_putstr
#else
-static void putstr(const char *ptr);
-
-#include <linux/compiler.h>
-#include <mach/uncompress.h>
-
-#ifdef CONFIG_DEBUG_ICEDCC
-
-#ifdef CONFIG_CPU_V6
-
-static void icedcc_putc(int ch)
-{
- int status, i = 0x4000000;
-
- do {
- if (--i < 0)
- return;
-
- asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
- } while (status & (1 << 29));
-
- asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
-}
-
-#else
-
-static void icedcc_putc(int ch)
-{
- int status, i = 0x4000000;
-
- do {
- if (--i < 0)
- return;
-
- asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
- } while (status & 2);
-
- asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
-}
-
-#endif
-
-#define putc(ch) icedcc_putc(ch)
-#define flush() do { } while (0)
-#endif
-
static void putstr(const char *ptr)
{
char c;
@@ -332,3 +290,149 @@ int main()
}
#endif
+#if defined(CONFIG_DEBUG_ICEDCC) || defined(CONFIG_DEBUG_RVIDCC)
+
+#define _DCC_ARM9_RBIT (1 << 0)
+#define _DCC_ARM9_WBIT (1 << 1)
+#define _DCC_ARM10_RBIT (1 << 7)
+#define _DCC_ARM10_WBIT (1 << 6)
+#define _DCC_ARM11_RBIT (1 << 30)
+#define _DCC_ARM11_WBIT (1 << 29)
+
+#define _READ_CORE_ID(x) { __asm__ ("mrc p15, 0, %0, c0, c0, 0\n" : "=r" (x)); \
+ x = (x >> 4) & 0xFFF; }
+
+#define _WRITE_ARM9_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x))
+#define _READ_ARM9_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x))
+#define _STATUS_ARM9_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x))
+#define _CAN_READ_ARM9_DCC(x) {_STATUS_ARM9_DCC(x); x &= _DCC_ARM9_RBIT;}
+#define _CAN_WRITE_ARM9_DCC(x) {_STATUS_ARM9_DCC(x); x &= _DCC_ARM9_WBIT; x = (x==0);}
+
+#define _WRITE_ARM10_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
+#define _READ_ARM10_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
+#define _STATUS_ARM10_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
+#define _CAN_READ_ARM10_DCC(x) {_STATUS_ARM10_DCC(x); x &= _DCC_ARM10_RBIT;}
+#define _CAN_WRITE_ARM10_DCC(x) {_STATUS_ARM10_DCC(x); x &= _DCC_ARM10_WBIT; x = (x==0);}
+
+#define _WRITE_ARM11_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
+#define _READ_ARM11_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
+#define _STATUS_ARM11_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
+#define _CAN_READ_ARM11_DCC(x) {_STATUS_ARM11_DCC(x); x &= _DCC_ARM11_RBIT;}
+#define _CAN_WRITE_ARM11_DCC(x) {_STATUS_ARM11_DCC(x); x &= _DCC_ARM11_WBIT; x = (x==0);}
+
+#define TIMEOUT_COUNT 0x4000000
+
+void icedcc_putc(unsigned int ch)
+{
+ static enum {unknown, arm9_and_earlier, arm10, arm11_and_later} _arm_type = unknown;
+ static int has_timed_out = 0;
+
+ if (has_timed_out)
+ return;
+
+ if (_arm_type == unknown)
+ {
+ register unsigned int id;
+ _READ_CORE_ID(id);
+
+ if ((id & 0xF00) == 0xA00)
+ _arm_type = arm10;
+ else if (id >= 0xb00)
+ _arm_type = arm11_and_later;
+ else
+ _arm_type = arm9_and_earlier;
+ }
+
+ if (_arm_type == arm9_and_earlier)
+ {
+ register unsigned int reg;
+ unsigned int timeout_count = TIMEOUT_COUNT;
+ while (--timeout_count)
+ {
+ _CAN_WRITE_ARM9_DCC(reg);
+ if (reg)
+ break;
+ }
+ if (timeout_count == 0)
+ has_timed_out = 1;
+ else
+ _WRITE_ARM9_DCC(ch);
+ }
+ else if (_arm_type == arm10)
+ {
+ register unsigned int reg;
+ unsigned int timeout_count = TIMEOUT_COUNT;
+ while (--timeout_count)
+ {
+ _CAN_WRITE_ARM10_DCC(reg);
+ if (reg)
+ break;
+ }
+ if (timeout_count == 0)
+ has_timed_out = 1;
+ else
+ _WRITE_ARM10_DCC(ch);
+ }
+ else
+ {
+ register unsigned int reg;
+ unsigned int timeout_count = TIMEOUT_COUNT;
+ while (--timeout_count)
+ {
+ _CAN_WRITE_ARM11_DCC(reg);
+ if (reg)
+ break;
+ }
+ if (timeout_count == 0)
+ has_timed_out = 1;
+ else
+ _WRITE_ARM11_DCC(ch);
+ }
+}
+
+static void icedcc_putstr(const char *ptr)
+{
+#if defined(CONFIG_DEBUG_ICEDCC)
+ for (; *ptr != '\0'; ptr++)
+ icedcc_putc(*ptr);
+#else
+ unsigned int sendbuf[16];
+ unsigned short cnt;
+ char *ptr1 = (char*)&sendbuf[1];
+ unsigned int *wordptr;
+
+ for (cnt=0; *ptr != '\0'; ptr++)
+ {
+ if (*ptr == '\n')
+ {
+ *ptr1++ = '\r';
+ cnt++;
+ }
+ *ptr1++ = *ptr;
+ cnt++;
+ }
+
+ *sendbuf = 0xa5580000 | cnt;
+
+ while(cnt % 4)
+ {
+ *ptr1++ = '\0';
+ cnt++;
+ }
+
+ cnt /= 4;
+
+#ifdef CONFIG_DEBUG_DCC_RAW
+ wordptr = &sendbuf[1];
+#else
+ wordptr = &sendbuf[0];
+ cnt++;
+#endif
+
+ while(cnt--)
+ icedcc_putc(*wordptr++);
+
+#endif
+}
+
+#endif
diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
index 153a07e7222b..a5924b9b88bd 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.in
+++ b/arch/arm/boot/compressed/vmlinux.lds.in
@@ -11,6 +11,11 @@ OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
+ /DISCARD/ : {
+ *(.ARM.exidx*)
+ *(.ARM.extab*)
+ }
+
. = TEXT_START;
_text = .;
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index a2cd9beaf37d..1ecf3f9fb375 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -4,6 +4,9 @@ config ARM_GIC
config ARM_VIC
bool
+config ARM_NVIC
+ bool
+
config ICST525
bool
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 7cb7961d81cb..0adef7fca2f9 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_ARM_GIC) += gic.o
obj-$(CONFIG_ARM_VIC) += vic.o
+obj-$(CONFIG_ARM_NVIC) += nvic.o
obj-$(CONFIG_ICST525) += icst525.o
obj-$(CONFIG_ICST307) += icst307.o
obj-$(CONFIG_SA1111) += sa1111.o
@@ -18,3 +19,5 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o
obj-$(CONFIG_ARCH_IXP23XX) += uengine.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
obj-$(CONFIG_COMMON_CLKDEV) += clkdev.o
+obj-$(CONFIG_DEBUG_RVIDCC) += rvidcc.o
+rvidcc-objs := rvidcc_common.o rvidcc_linux.o
diff --git a/arch/arm/common/nvic.c b/arch/arm/common/nvic.c
new file mode 100644
index 000000000000..ea40cc8c7927
--- /dev/null
+++ b/arch/arm/common/nvic.c
@@ -0,0 +1,99 @@
+/*
+ * linux/arch/arm/common/nvic.c
+ *
+ * Copyright (C) 2008 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Support for the Nested Vectored Interrupt Controller found on the
+ * ARMv7-M CPUs (Cortex-M3)
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/nvic.h>
+
+static DEFINE_SPINLOCK(irq_controller_lock);
+
+/*
+ * Routines to acknowledge, disable and enable interrupts
+ *
+ * Linux assumes that when we're done with an interrupt we need to
+ * unmask it, in the same way we need to unmask an interrupt when
+ * we first enable it.
+ *
+ * The NVIC has a separate notion of "end of interrupt" to re-enable
+ * an interrupt after handling, in order to support hardware
+ * prioritisation.
+ *
+ * We can make the NVIC behave in the way that Linux expects by making
+ * our "acknowledge" routine disable the interrupt, then mark it as
+ * complete.
+ */
+static void nvic_ack_irq(unsigned int irq)
+{
+ u32 mask = 1 << (irq % 32);
+
+ spin_lock(&irq_controller_lock);
+ writel(mask, NVIC_CLEAR_ENABLE + irq / 32 * 4);
+ spin_unlock(&irq_controller_lock);
+}
+
+static void nvic_mask_irq(unsigned int irq)
+{
+ u32 mask = 1 << (irq % 32);
+
+ spin_lock(&irq_controller_lock);
+ writel(mask, NVIC_CLEAR_ENABLE + irq / 32 * 4);
+ spin_unlock(&irq_controller_lock);
+}
+
+static void nvic_unmask_irq(unsigned int irq)
+{
+ u32 mask = 1 << (irq % 32);
+
+ spin_lock(&irq_controller_lock);
+ writel(mask, NVIC_SET_ENABLE + irq / 32 * 4);
+ spin_unlock(&irq_controller_lock);
+}
+
+static struct irq_chip nvic_chip = {
+ .name = "NVIC",
+ .ack = nvic_ack_irq,
+ .mask = nvic_mask_irq,
+ .unmask = nvic_unmask_irq,
+};
+
+void __init nvic_init(void)
+{
+ unsigned int max_irq, i;
+
+ max_irq = ((readl(NVIC_INTR_CTRL) & 0x1f) + 1) * 32;
+
+ /*
+ * Disable all interrupts
+ */
+ for (i = 0; i < max_irq / 32; i++)
+ writel(~0, NVIC_CLEAR_ENABLE + i * 4);
+
+ /*
+ * Set priority on all interrupts.
+ */
+ for (i = 0; i < max_irq; i += 4)
+ writel(0, NVIC_PRIORITY + i);
+
+ /*
+ * Setup the Linux IRQ subsystem.
+ */
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_chip(i, &nvic_chip);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+}
diff --git a/arch/arm/common/rvidcc_common.c b/arch/arm/common/rvidcc_common.c
new file mode 100644
index 000000000000..3e21709095d0
--- /dev/null
+++ b/arch/arm/common/rvidcc_common.c
@@ -0,0 +1,794 @@
+/*
+ Copyright (C) 2004-2007 ARM Limited.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+*/
+
+/* ================================================================
+ Universal RealView ICE DCC communications driver - How to use it
+ ================================================================
+
+ This driver is split into 2 sections: a generic section (this file) that
+ handles the DCC hardware access and buffering and an OS-dependent file that
+ integrates the driver into the OS network and TTY layers. The interface
+ between the sections is defined in rvidcc_interface.h, which contains
+ prototypes and documentation for the functions in the generic section that
+ can be called from the OS-dependent section and the callback functions
+ called from the generic section that must be provided by the OS-dependent
+ section.
+
+ This driver is designed to be able to work with or without interrupts, to
+ use raw DCC comms (as a TTY) or virtual Ethernet. The driver is configured
+ in the rvidcc_config.h header, including options to select which cores to
+ support, whether to support ethernet, buffer sizes and how to
+ enable/disable interrupts. See the example configs for details of all
+ options.
+
+ All buffers used by the driver are in the system memory space. All
+ pointer arguments for functions called by or from the generic section are
+ pointers to system memory. It is the responsibility of the OS-dependent
+ section to copy to/from user memory.
+
+ ARM Ltd. highly recommends using interrupt-driven DCC communications, and
+ to use the virtual Ethernet system, even if only a TTY is required.
+
+ Raw DCC communications transfers data in 32-bit words. Thus if virtual
+ Ethernet is not used, data transfers will contain null padding for blocks
+ of data that do not have a multiple of 4 bytes. For most command-line
+ applications, this is unacceptable. However protocols, such as the remote
+ gdb protocol, will tolerate the extra nulls, provided they occur between
+ packets. This, of course, requires that data be passed to the driver as
+ packets, and not as byte-by-byte as some TTY drivers are in the habit of
+ doing.
+
+ Using the virtual Ethernet system does not force you to have to support
+ networking, or an IP stack, etc. The virtual Ethernet system contains a
+ TTY channel and an Ethernet channel, and if only the TTY channel is
+ required, the Ethernet channel and its data can be ignored. Using this
+ for TTY only has the advantage that data packets do not have to be a
+ multiple of 4 bytes, and so it is suitable for command-line consoles.
+
+ The virtual Ethernet system is not true Ethernet in that it can only carry
+ IP traffic. It does, however, have a mechanism for obtaining a unique MAC
+ address from the ICE, and the target will receive ARP-style queries to
+ determine if the target has a particular IP address. Thus DHCP can be used
+ to obtain an IP address from an external DHCP server, without the need for
+ any special configuration of the ICE.
+*/
+
+#include "rvidcc_config.h"
+#include "rvidcc_interface.h"
+
+
+#ifdef __ARMCC_VERSION
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+
+#ifndef RVIDCC_RAW
+
+#define UNCOMP_TTY_START 0xa5580000
+#define UNCOMP_ETH_START 0xa55a0000
+#define START_MASK 0xfffc0000
+#define START_SENTINEL UNCOMP_TTY_START
+
+#endif /* RVIDCC_RAW */
+
+#if !defined(RVIDCC_ARM79) && !defined(RVIDCC_ARM10) && !defined(RVIDCC_ARM11)
+#warning No cores are enabled. Define at least one of RVIDCC_ARM79, RVIDCC_ARM10 or RVIDCC_ARM11
+#endif
+
+
+#define DCC_ARM9_RBIT (1 << 0)
+#define DCC_ARM9_WBIT (1 << 1)
+#define DCC_ARM10_RBIT (1 << 7)
+#define DCC_ARM10_WBIT (1 << 6)
+#define DCC_ARM11_RBIT (1 << 30)
+#define DCC_ARM11_WBIT (1 << 29)
+
+/* Access primitives: x must be unsigned int */
+
+#ifdef __ARMCC_VERSION
+
+/* RVCT versions */
+#define READ_CORE_ID(x) { __asm { mrc p15, 0, x, c0, c0, 0 } \
+ x = (x >> 4) & 0xFFF; }
+
+#ifdef RVIDCC_ARM79
+#define WRITE_ARM9_DCC(x) __asm { mcr p14, 0, x, c1, c0, 0 }
+#define READ_ARM9_DCC(x) __asm { mrc p14, 0, x, c1, c0, 0 }
+#define STATUS_ARM9_DCC(x) __asm { mrc p14, 0, x, c0, c0, 0 }
+#define CAN_READ_ARM9_DCC(x) {STATUS_ARM9_DCC(x); x &= DCC_ARM9_RBIT;}
+#define CAN_WRITE_ARM9_DCC(x) {STATUS_ARM9_DCC(x); x &= DCC_ARM9_WBIT; x = (x==0);}
+#endif
+
+#ifdef RVIDCC_ARM10
+#define WRITE_ARM10_DCC(x) __asm { mcr p14, 0, x, c0, c5, 0 }
+#define READ_ARM10_DCC(x) __asm { mrc p14, 0, x, c0, c5, 0 }
+#define STATUS_ARM10_DCC(x) __asm { mrc p14, 0, x, c0, c1, 0 }
+#define CAN_READ_ARM10_DCC(x) {STATUS_ARM10_DCC(x); x &= DCC_ARM10_RBIT;}
+#define CAN_WRITE_ARM10_DCC(x) {STATUS_ARM10_DCC(x); x &= DCC_ARM10_WBIT; x = (x==0);}
+#endif
+
+#ifdef RVIDCC_ARM11
+#define WRITE_ARM11_DCC(x) __asm { mcr p14, 0, x, c0, c5, 0 }
+#define READ_ARM11_DCC(x) __asm { mrc p14, 0, x, c0, c5, 0 }
+#define STATUS_ARM11_DCC(x) __asm { mrc p14, 0, x, c0, c1, 0 }
+#define CAN_READ_ARM11_DCC(x) {STATUS_ARM11_DCC(x); x &= DCC_ARM11_RBIT;}
+#define CAN_WRITE_ARM11_DCC(x) {STATUS_ARM11_DCC(x); x &= DCC_ARM11_WBIT; x = (x==0);}
+#endif
+
+#else
+
+/* GCC versions */
+#define READ_CORE_ID(x) { __asm__ ("mrc p15, 0, %0, c0, c0, 0\n" : "=r" (x)); \
+ x = (x >> 4) & 0xFFF; }
+
+#ifdef RVIDCC_ARM79
+#define WRITE_ARM9_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x))
+#define READ_ARM9_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x))
+#define STATUS_ARM9_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x))
+#define CAN_READ_ARM9_DCC(x) {STATUS_ARM9_DCC(x); x &= DCC_ARM9_RBIT;}
+#define CAN_WRITE_ARM9_DCC(x) {STATUS_ARM9_DCC(x); x &= DCC_ARM9_WBIT; x = (x==0);}
+#endif
+
+#ifdef RVIDCC_ARM10
+#define WRITE_ARM10_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
+#define READ_ARM10_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
+#define STATUS_ARM10_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
+#define CAN_READ_ARM10_DCC(x) {STATUS_ARM10_DCC(x); x &= DCC_ARM10_RBIT;}
+#define CAN_WRITE_ARM10_DCC(x) {STATUS_ARM10_DCC(x); x &= DCC_ARM10_WBIT; x = (x==0);}
+#endif
+
+#ifdef RVIDCC_ARM11
+#define WRITE_ARM11_DCC(x) __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
+#define READ_ARM11_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
+#define STATUS_ARM11_DCC(x) __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
+#define CAN_READ_ARM11_DCC(x) {STATUS_ARM11_DCC(x); x &= DCC_ARM11_RBIT;}
+#define CAN_WRITE_ARM11_DCC(x) {STATUS_ARM11_DCC(x); x &= DCC_ARM11_WBIT; x = (x==0);}
+#endif
+
+#endif
+
+static enum {arm9_and_earlier, arm10, arm11_and_later} arm_type = arm9_and_earlier;
+
+/* Prototypes */
+static void rvidcc_write_lowlevel(const void *ptr, size_t len);
+
+/* Queues */
+
+struct ringbuffer
+{
+ unsigned char *buf;
+ size_t size;
+ unsigned char* readPtr;
+ unsigned char* writePtr;
+};
+
+static unsigned char dcc_inbuffer[RVIDCC_BUFSIZE];
+static struct ringbuffer dcc_inbuf;
+static unsigned char dcc_outbuffer[RVIDCC_BUFSIZE];
+static struct ringbuffer dcc_outbuf;
+
+#ifndef RVIDCC_RAW
+#define DCC_TTY_INBUF_SIZE (RVIDCC_BUFSIZE/2)
+static unsigned char dcc_temp_source[DCC_TTY_INBUF_SIZE];
+static unsigned char dcc_tty_inbuffer[DCC_TTY_INBUF_SIZE];
+static struct ringbuffer dcc_tty_inbuf;
+#define DCC_TTY_INBUF dcc_tty_inbuf
+
+#else
+
+#define DCC_TTY_INBUF dcc_inbuf
+
+#endif
+
+
+/* This ringbuffer has no locks as it assumes only 1 reader and 1 writer and
+ * assumes a 32-bit access is atomic */
+INLINE static void ringbuf_advance_read(struct ringbuffer* ring_buf, size_t amount)
+{
+ unsigned char* temptr = ring_buf->readPtr + amount;
+ while (temptr >= ring_buf->buf + ring_buf->size)
+ temptr -= ring_buf->size;
+ ring_buf->readPtr = temptr;
+}
+
+
+INLINE static void ringbuf_advance_write(struct ringbuffer* ring_buf, size_t amount)
+{
+ unsigned char* temptr = ring_buf->writePtr + amount;
+ while (temptr >= ring_buf->buf + ring_buf->size)
+ temptr -= ring_buf->size;
+ ring_buf->writePtr = temptr;
+}
+
+
+INLINE static void ringbuf_get(struct ringbuffer* ring_buf,
+ unsigned char* dst, size_t amount)
+{
+ unsigned char* source = ring_buf->readPtr;
+ size_t len_to_end = ring_buf->buf + ring_buf->size - source;
+ if (amount > len_to_end)
+ {
+ memcpy(dst, source, len_to_end);
+ memcpy(dst + len_to_end, ring_buf->buf, (amount - len_to_end));
+ }
+ else
+ memcpy(dst, source, amount);
+}
+
+
+INLINE static void ringbuf_put(struct ringbuffer* ring_buf,
+ unsigned char* src, size_t amount)
+{
+ unsigned char* dest = ring_buf->writePtr;
+ unsigned int len_to_end = ring_buf->buf + ring_buf->size - dest;
+ if (amount > len_to_end)
+ {
+ memcpy(dest, src, len_to_end);
+ memcpy(ring_buf->buf, src + len_to_end, amount - len_to_end);
+ }
+ else
+ memcpy(dest, src, amount);
+}
+
+
+INLINE static size_t ringbuf_available_data(struct ringbuffer* ring_buf)
+{
+ int avail = ring_buf->writePtr - ring_buf->readPtr;
+
+ if (avail < 0)
+ /* handle wrap around */
+ avail += ring_buf->size;
+
+ return (size_t)avail;
+}
+
+
+INLINE static size_t ringbuf_available_space(struct ringbuffer* ring_buf)
+{
+ size_t avail;
+
+ if (ring_buf->writePtr >= ring_buf->readPtr)
+ avail = ring_buf->size - (ring_buf->writePtr - ring_buf->readPtr) - 1;
+ else
+ avail = ring_buf->readPtr - ring_buf->writePtr - 1;
+
+ return avail;
+}
+
+
+// conditionally swap endian of a 32bit word
+#ifdef RVIDCC_BIG_ENDIAN
+#define to_little_endian(x) ((((x)&0xff) << 24) | (((x)&0xff00) << 8) | (((x)&0xff0000) >> 8) | (((x)&0xff000000) >> 24))
+#else
+#define to_little_endian(x) (x)
+#endif
+
+
+int rvidcc_init(void)
+{
+ register unsigned int id;
+ int err = 0;
+#ifndef RVIDCC_RAW
+ unsigned int macRequest = to_little_endian(UNCOMP_ETH_START);
+#endif
+
+ RVIDCC_DISABLE_INTERRUPTS;
+
+ /* check core type, raising error if core not supported */
+ READ_CORE_ID(id);
+ if ((id & 0xF00) == 0xA00)
+ {
+ arm_type = arm10;
+#ifndef RVIDCC_ARM10
+ err = RVIDCC_ERR_CORE_NOT_SUPPORTED;
+#endif
+ }
+ else if (id >= 0xb00)
+ {
+ arm_type = arm11_and_later;
+#ifndef RVIDCC_ARM11
+ err = RVIDCC_ERR_CORE_NOT_SUPPORTED;
+#endif
+ }
+ else
+ {
+ arm_type = arm9_and_earlier;
+#ifndef RVIDCC_ARM79
+ err = RVIDCC_ERR_CORE_NOT_SUPPORTED;
+#endif
+ }
+
+ if (!err)
+ {
+ dcc_inbuf.buf = dcc_inbuffer;
+ dcc_inbuf.size = RVIDCC_BUFSIZE;
+ dcc_inbuf.readPtr = dcc_inbuf.buf;
+ dcc_inbuf.writePtr = dcc_inbuf.buf;
+
+ dcc_outbuf.buf = dcc_outbuffer;
+ dcc_outbuf.size = RVIDCC_BUFSIZE;
+ dcc_outbuf.readPtr = dcc_outbuf.buf;
+ dcc_outbuf.writePtr = dcc_outbuf.buf;
+
+#ifndef RVIDCC_RAW
+ dcc_tty_inbuf.buf = dcc_tty_inbuffer;
+ dcc_tty_inbuf.size = DCC_TTY_INBUF_SIZE;
+ dcc_tty_inbuf.readPtr = dcc_tty_inbuf.buf;
+ dcc_tty_inbuf.writePtr = dcc_tty_inbuf.buf;
+
+ /* request a MAC address */
+ rvidcc_write_lowlevel(&macRequest, sizeof(unsigned int));
+#endif
+
+ /* Enable interrupts (write interrupt will be enabled when something is written) */
+ RVIDCC_ENABLE_READ_INTERRUPT;
+ RVIDCC_ENABLE_INTERRUPTS;
+ }
+
+ return err;
+}
+
+
+void rvidcc_write(void)
+{
+ register unsigned int reg;
+ int pollcount = -1;
+ int some_transfer = 0;
+
+ switch (arm_type)
+ {
+#ifdef RVIDCC_ARM79
+ case arm9_and_earlier:
+ {
+ /* Try to write everything available */
+ while (ringbuf_available_data(&dcc_outbuf) >= sizeof(unsigned int))
+ {
+ /* On the first word, the write is aborted immediately if the DCC write
+ * register is full. On subsequent words, the driver waits for a
+ * bit (RVIDCC_MAX_INLINE_POLLS times) as the RVI will probably
+ * read the DCC register soon because it knows data is being sent. */
+ do
+ {
+ CAN_WRITE_ARM9_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ reg = to_little_endian(*(unsigned int *)dcc_outbuf.readPtr);
+ WRITE_ARM9_DCC(reg);
+ ringbuf_advance_read(&dcc_outbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+
+ pollcount = -1;
+ break;
+ }
+#endif
+
+#ifdef RVIDCC_ARM10
+ case arm10:
+ {
+ /* Try to write everything available */
+ while (ringbuf_available_data(&dcc_outbuf) >= sizeof(unsigned int))
+ {
+ do
+ {
+ CAN_WRITE_ARM10_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ reg = to_little_endian(*(unsigned int *)dcc_outbuf.readPtr);
+ WRITE_ARM10_DCC(reg);
+ ringbuf_advance_read(&dcc_outbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+
+ pollcount = -1;
+ break;
+ }
+#endif
+
+#ifdef RVIDCC_ARM11
+ case arm11_and_later:
+ {
+ /* Try to write everything available */
+ while (ringbuf_available_data(&dcc_outbuf) >= sizeof(unsigned int))
+ {
+ do
+ {
+ CAN_WRITE_ARM11_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ reg = to_little_endian(*(unsigned int *)dcc_outbuf.readPtr);
+ WRITE_ARM11_DCC(reg);
+ ringbuf_advance_read(&dcc_outbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+
+ pollcount = -1;
+ break;
+ }
+#endif
+
+ default:
+ break;
+ }
+
+ if (some_transfer)
+ rvidcc_cb_notify();
+
+ /* Disable interrupt if nothing left to write */
+ if (ringbuf_available_data(&dcc_outbuf) == 0)
+ RVIDCC_DISABLE_WRITE_INTERRUPT;
+}
+
+
+/* this routine assumes it is non-interruptible by others that access the queue pointers */
+/* this is written out longhand because it may be called from an interrupt routine */
+void rvidcc_read(void)
+{
+ register unsigned int reg;
+ int pollcount = -1;
+ int some_transfer = 0;
+
+ switch (arm_type)
+ {
+#ifdef RVIDCC_ARM79
+ case arm9_and_earlier:
+ {
+ /* Try to read everything available */
+ while (ringbuf_available_space(&dcc_inbuf) >= sizeof(unsigned int))
+ {
+ do
+ {
+ CAN_READ_ARM9_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ READ_ARM9_DCC(reg);
+ *(unsigned int *)dcc_inbuf.writePtr = to_little_endian(reg);
+ ringbuf_advance_write(&dcc_inbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+ break;
+ }
+#endif
+
+#ifdef RVIDCC_ARM10
+ case arm10:
+ {
+ /* Try to read everything available */
+ while (ringbuf_available_space(&dcc_inbuf) >= sizeof(unsigned int))
+ {
+ do
+ {
+ CAN_READ_ARM10_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ READ_ARM10_DCC(reg);
+ *(unsigned int *)dcc_inbuf.writePtr = to_little_endian(reg);
+ ringbuf_advance_write(&dcc_inbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+ break;
+ }
+#endif
+
+#ifdef RVIDCC_ARM11
+ case arm11_and_later:
+ {
+ /* Try to read everything available */
+ while (ringbuf_available_space(&dcc_inbuf) >= sizeof(unsigned int))
+ {
+ do
+ {
+ CAN_READ_ARM11_DCC(reg);
+ } while (!reg && pollcount != -1 && --pollcount > 0);
+
+ if (!reg)
+ break;
+
+ READ_ARM11_DCC(reg);
+ *(unsigned int *)dcc_inbuf.writePtr = to_little_endian(reg);
+ ringbuf_advance_write(&dcc_inbuf, sizeof(unsigned int));
+ pollcount = RVIDCC_MAX_INLINE_POLLS;
+ some_transfer = 1;
+ }
+ break;
+ }
+#endif
+
+ default:
+ break;
+ }
+
+ if (ringbuf_available_space(&dcc_inbuf) == 0)
+ RVIDCC_DISABLE_READ_INTERRUPT;
+
+ if (some_transfer)
+ rvidcc_cb_notify();
+}
+
+
+/* this routine assumes it is not interrupted by others that access the queue pointers */
+void rvidcc_poll(void)
+{
+ rvidcc_write();
+ rvidcc_read();
+}
+
+
+#ifndef RVIDCC_RAW
+void rvidcc_process(void)
+{
+ unsigned int sentinel = 0;
+ int compsize = 0;
+
+ /* Process received data */
+ while (ringbuf_available_data(&dcc_inbuf) >= sizeof(unsigned int))
+ {
+ int bytes;
+ unsigned char *buf;
+
+ /* Search for start sentinel */
+ sentinel = to_little_endian(*(unsigned int *)dcc_inbuf.readPtr);
+ compsize = sentinel & 0xffff;
+
+ /* Discard if not a start sentinel */
+ if ((sentinel & START_MASK) != START_SENTINEL ||
+ compsize > sizeof(dcc_temp_source) || compsize <= 0)
+ {
+ ringbuf_advance_read(&dcc_inbuf, sizeof(unsigned int));
+ continue;
+ }
+
+ /* Sentinel found, come back later if not enough data */
+ bytes = ringbuf_available_data(&dcc_inbuf);
+ if (bytes < compsize + sizeof(unsigned int))
+ break;
+
+ /* Copy to a contiguous buffer */
+ ringbuf_get(&dcc_inbuf,
+ dcc_temp_source, compsize + sizeof(unsigned int));
+
+ sentinel &= 0xffff0000;
+ buf = dcc_temp_source + sizeof(unsigned int);
+
+ bytes = compsize;
+
+ /* Round up to nearest whole word */
+ if (compsize & 0x3)
+ compsize = (compsize + 4) & ~0x3;
+
+ /* advance by packet size + sentinel */
+ ringbuf_advance_read(&dcc_inbuf, compsize + sizeof(unsigned int));
+
+ /* allow more data to be received */
+ RVIDCC_ENABLE_READ_INTERRUPT;
+
+ /* Process TTY or IP packet accordingly */
+ if (sentinel == UNCOMP_TTY_START)
+ {
+ ringbuf_put(&dcc_tty_inbuf, buf, bytes);
+ ringbuf_advance_write(&dcc_tty_inbuf, bytes);
+ }
+ else
+ {
+ if (bytes == 4) /* ARP 'is this IP address you?' */
+ {
+ if (rvidcc_cb_has_addr(buf))
+ rvidcc_transmit_ip_packet(buf, 4);
+ }
+ else if (bytes == 6) /* set MAC address */
+ rvidcc_cb_set_mac_address(buf);
+ else
+ rvidcc_cb_ip_packet_received(buf, (size_t)bytes);
+ }
+ }
+}
+#endif
+
+
+#ifdef RVIDCC_SCAN_INPUT_FOR
+int rvidcc_scan_input_for(char c, size_t span)
+{
+ int ret = 0;
+
+ size_t bytesAvail = ringbuf_available_data(&DCC_TTY_INBUF);
+ if (bytesAvail && span)
+ {
+ unsigned char *p = DCC_TTY_INBUF.readPtr;
+
+ if (span > bytesAvail)
+ span = bytesAvail;
+
+ while (span--)
+ {
+ if (*p++ == c)
+ {
+ ret = 1;
+ break;
+ }
+
+ if (p >= DCC_TTY_INBUF.buf + DCC_TTY_INBUF.size)
+ p = DCC_TTY_INBUF.buf;
+ }
+ }
+ return ret;
+}
+#endif
+
+
+#ifdef RVIDCC_OUTBUF_DATA
+size_t rvidcc_outbuf_data(void)
+{
+ return ringbuf_available_data(&dcc_outbuf);
+}
+#endif
+
+
+size_t rvidcc_serial_can_read(void)
+{
+ return ringbuf_available_data(&DCC_TTY_INBUF);
+}
+
+
+size_t rvidcc_serial_can_write(void)
+{
+ size_t space = ringbuf_available_space(&dcc_outbuf);
+
+ // protocol only has 16 bits for packet size, so limit packets to this size
+ if (space > (65536 - 4))
+ space = (65536 - 4);
+
+ return space;
+}
+
+
+size_t rvidcc_read_serial(void *ptr, size_t len)
+{
+ size_t bytes = ringbuf_available_data(&DCC_TTY_INBUF);
+ if (bytes && len)
+ {
+ if (bytes > len)
+ bytes = len;
+
+ ringbuf_get(&DCC_TTY_INBUF, (unsigned char*)ptr, bytes);
+#ifdef RVIDCC_RAW
+ /* round up to 4 bytes */
+ if (bytes & 0x3)
+ ringbuf_advance_read(&DCC_TTY_INBUF, ((bytes + 4) & ~0x3));
+ else
+ ringbuf_advance_read(&DCC_TTY_INBUF, bytes);
+
+ RVIDCC_ENABLE_READ_INTERRUPT;
+#else
+ ringbuf_advance_read(&DCC_TTY_INBUF, bytes);
+#endif
+ }
+ else
+ bytes = 0;
+
+ return bytes;
+}
+
+
+static void rvidcc_write_lowlevel(const void *ptr, size_t len)
+{
+ size_t rem;
+
+ ringbuf_put(&dcc_outbuf, (unsigned char*)ptr, len);
+
+ ringbuf_advance_write(&dcc_outbuf, len & ~0x3); // advance whole words
+
+ /* ensure excess bytes up to word boundary are null */
+ rem = (len & 0x3);
+ if (rem)
+ {
+ for (; rem < 4; rem++)
+ *(dcc_outbuf.writePtr + rem) = '\0';
+
+ ringbuf_advance_write(&dcc_outbuf, sizeof(unsigned long)); // advance remainder word
+ }
+
+
+ RVIDCC_ENABLE_WRITE_INTERRUPT;
+}
+
+
+size_t rvidcc_write_serial(const void *ptr, size_t len)
+{
+ size_t bytes;
+#ifndef RVIDCC_RAW
+ unsigned long sentinel;
+#endif
+
+ bytes = rvidcc_serial_can_write();
+
+#ifndef RVIDCC_RAW
+ if (bytes > sizeof(unsigned long))
+ {
+ /* Size limit the amount of data to be written, allowing for sentinel */
+ if (len > (bytes - sizeof(unsigned long)))
+ len = (bytes - sizeof(unsigned long));
+
+ sentinel = to_little_endian(UNCOMP_TTY_START | (unsigned short)len);
+ rvidcc_write_lowlevel(&sentinel, sizeof(unsigned long));
+ rvidcc_write_lowlevel(ptr, len);
+ }
+#else
+ if (bytes > 0)
+ {
+ /* Size limit the amount of data to be written */
+ if (len > bytes)
+ len = bytes;
+
+ rvidcc_write_lowlevel(ptr, len);
+ }
+#endif
+ else
+ len = 0;
+
+ return len;
+}
+
+
+#ifndef RVIDCC_RAW
+int rvidcc_transmit_ip_packet(void *packet, size_t length)
+{
+ if (rvidcc_serial_can_write() >= (length + 4))
+ {
+ unsigned long sentinel = to_little_endian(UNCOMP_ETH_START | (unsigned short)length);
+ rvidcc_write_lowlevel(&sentinel, 4);
+ rvidcc_write_lowlevel(packet, length);
+ }
+ else
+ length = 0;
+
+ return length;
+}
+#endif
+
+/* End of file */
diff --git a/arch/arm/common/rvidcc_config.h b/arch/arm/common/rvidcc_config.h
new file mode 100644
index 000000000000..faabe1db1b59
--- /dev/null
+++ b/arch/arm/common/rvidcc_config.h
@@ -0,0 +1,166 @@
+/*
+ Copyright (C) 2004-2007 ARM Limited.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+*/
+
+#ifndef RVIDCC_CONFIG_H
+#define RVIDCC_CONFIG_H
+
+/*
+ *
+ * Platform headers that define basic types (e.g. size_t)
+ * ------------------------------------------------------
+ *
+ */
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+
+/*
+ * Put any platform specific definitions required by the interrupt macros here
+ * ---------------------------------------------------------------------------
+ */
+
+/* Structure containing our internal state, etc. */
+struct dccconfig
+{
+ unsigned int rx_interrupt;
+ unsigned int tx_interrupt;
+ unsigned long timer_poll_period;
+ int use_timer_poll;
+
+ volatile unsigned long irq_disable;
+};
+
+extern struct dccconfig dcc_config;
+
+
+/*
+ * Configuration
+ * -------------
+ */
+
+/*
+ * Define which ARM cores this binary is to be used on
+ * - RVIDCC_ARM79 for all ARM 7 and ARM 9 based cores
+ * - RVIDCC_ARM10 for all ARM 10 cores
+ * - RVIDCC_ARM11 for all ARM 11 and later cores (including Cortex)
+ */
+#define RVIDCC_ARM79
+#define RVIDCC_ARM10
+#define RVIDCC_ARM11
+
+/*
+ * Define RVIDCC_OUTBUF_DATA if the OS needs to check if all pending data
+ * has been sent out to the ICE.
+ */
+#define RVIDCC_OUTBUF_DATA
+
+/*
+ * Define RVIDCC_RAW if the virtual ethernet functionality is not required. See
+ * rvidcc.c for more information.
+ */
+#ifdef CONFIG_DEBUG_DCC_RAW
+#define RVIDCC_RAW
+#endif
+
+/*
+ * Define RVIDCC_BIG_ENDIAN if your platform is big endian.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define RVIDCC_BIG_ENDIAN
+#endif
+
+/*
+ * Define RVIDCC_SCAN_INPUT_FOR if the OS needs to peek ahead in the TTY data
+ */
+#ifdef CONFIG_DEBUG_DCC_KGDB
+#define RVIDCC_SCAN_INPUT_FOR
+#endif
+
+/*
+ * RVIDCC_BUFSIZE defines the size of the input and output buffers for DCC data
+ */
+#ifndef RVIDCC_BUFSIZE
+#ifdef RVIDCC_RAW
+#define RVIDCC_BUFSIZE 4096
+#else
+#define RVIDCC_BUFSIZE 8192
+#endif
+#endif
+
+/*
+ * RVIDCC_MAX_INLINE_POLLS defines the number of times to the driver should
+ * check if the host is ready for more data in rvidcc_write or if the host has
+ * sent more data in rvidcc_read. Increasing this value may improve the data
+ * transfer rate, but will increase the length of time spent in the interrupt
+ * handler. Adjust this value according to the performance and latency
+ * requirements of the system.
+ */
+#define RVIDCC_MAX_INLINE_POLLS 500
+
+/*
+ * Interrupt configuration
+ *
+ * Define macros here to enable and disable interrupts. If the OS uses
+ * polling instead of interrupts, define as empty.
+ *
+ */
+
+#define RVIDCC_ENABLE_INTERRUPTS
+
+#define RVIDCC_DISABLE_INTERRUPTS
+
+/* Interrupt control macros */
+#define RVIDCC_ENABLE_WRITE_INTERRUPT do { \
+ if (!dcc_config.use_timer_poll) { \
+ if (test_and_clear_bit(0, &dcc_config.irq_disable)) \
+ enable_irq(dcc_config.tx_interrupt); \
+ } \
+ } while(0)
+
+#define RVIDCC_DISABLE_WRITE_INTERRUPT do { \
+ if (!dcc_config.use_timer_poll) { \
+ if (!test_and_set_bit(0, &dcc_config.irq_disable)) \
+ disable_irq(dcc_config.tx_interrupt); \
+ } \
+ } while(0)
+
+#define RVIDCC_ENABLE_READ_INTERRUPT do { \
+ if (!dcc_config.use_timer_poll) { \
+ if (test_and_clear_bit(1, &dcc_config.irq_disable)) \
+ enable_irq(dcc_config.rx_interrupt); \
+ } \
+ } while(0)
+
+#define RVIDCC_DISABLE_READ_INTERRUPT do { \
+ if (!dcc_config.use_timer_poll) { \
+ if (!test_and_set_bit(1, &dcc_config.irq_disable)) \
+ disable_irq(dcc_config.rx_interrupt); \
+ } \
+ } while(0)
+
+
+#endif /* RVIDCC_CONFIG_H */
diff --git a/arch/arm/common/rvidcc_interface.h b/arch/arm/common/rvidcc_interface.h
new file mode 100644
index 000000000000..9ccf439ce46e
--- /dev/null
+++ b/arch/arm/common/rvidcc_interface.h
@@ -0,0 +1,182 @@
+/*
+ Copyright (C) 2004-2007 ARM Limited.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+*/
+
+#ifndef RVIDCC_INTERFACE_H
+#define RVIDCC_INTERFACE_H
+
+/*
+ * These are the functions provided by the generic section that the OS-dependent
+ * section is allowed to call
+ */
+
+#define RVIDCC_ERR_CORE_NOT_SUPPORTED 1
+
+/* Initialise DCC comms driver.
+ *
+ * Note that this triggers the request to the RVI for a MAC address when using
+ * virtual Ethernet. Returns 0 on success, RVIDCC_ERR_* on failure
+ */
+extern int rvidcc_init(void);
+
+/* Poll for DCC communications.
+ *
+ * If interrupts are not being used then this should be called periodically,
+ * otherwise this is the interrupt handler for DCC communications.
+ */
+extern void rvidcc_poll(void);
+
+#ifndef RVIDCC_RAW
+/* Process received DCC data.
+ *
+ * This function is only relevant if using virtual Ethernet. This is a
+ * 'bottom half' routine and processes the data captured in rvidcc_poll(). If
+ * using interrupts, this routine should be scheduled to be called at the next
+ * available opportunity once the interrupt handler has completed. If not
+ * using interrupts then this can be called immediately on notification of the
+ * arrival of incoming data.
+ */
+extern void rvidcc_process(void);
+#endif
+
+/* Handle low level reading of dcc information
+ *
+ * This should be called from the interrupt handler for the dcc read interrupt
+ * to read data from the DCC register. It is also called by rvidcc_poll.
+ */
+extern void rvidcc_read(void);
+
+/* Handle low level writing of dcc information
+ *
+ * This should be called from the interrupt handler for the dcc write interrupt
+ * to write data to the DCC register. It is also called by rvidcc_poll.
+ */
+extern void rvidcc_write(void);
+
+#ifdef RVIDCC_OUTBUF_DATA
+/* Get the number of bytes left to be sent out to the ICE */
+extern size_t rvidcc_outbuf_data(void);
+#endif
+
+/* Get the number of bytes available for reading from TTY.
+ *
+ * Zero is returned if no data is available.
+ */
+extern size_t rvidcc_serial_can_read(void);
+
+/* Get the number of bytes that can be written to the TTY.
+ *
+ * Zero is returned if no data can be written.
+ */
+extern size_t rvidcc_serial_can_write(void);
+
+/* Read and consume incoming TTY data.
+ *
+ * This is the primary TTY read routine.
+ */
+extern size_t rvidcc_read_serial(void *ptr, size_t len);
+
+/* Write and queue up outgoing TTY data.
+ *
+ * This is the primary TTY write routine.
+ */
+extern size_t rvidcc_write_serial(const void *ptr, size_t len);
+
+/* Send an IP packet out to the virtual network.
+ *
+ * The data provided must be a valid IP packet and must not contain an
+ * Ethernet header. The data provided is all copied, if there is space on the
+ * queue, othewise none of it is and the packet should be treated as still
+ * pending. The return value is the number of bytes copied.
+ */
+extern int rvidcc_transmit_ip_packet(void *packet, size_t length);
+
+
+#ifdef RVIDCC_SCAN_INPUT_FOR
+/* Scan pending incoming TTY data for a character.
+ *
+ * This is primarily provided for detecting ^C (interrupt) on pending incoming
+ * TTY data, e.g. to allow a gdb stub to be re-activated when a program is
+ * running. It should be called from 'bottom half' processing, or from a
+ * regular poll. The scan starts at the latest character received and works
+ * backwards for a maximum of 'span' characters.
+ */
+extern int rvidcc_scan_input_for(char c, size_t span);
+#endif
+
+
+/*
+ * Callbacks
+ * These are called from the generic section (in rvidcc.c) and should be provided
+ * by the OS-dependent section.
+ */
+
+
+/* DCC incoming data notification callback.
+ *
+ * This is called by rvidcc_poll() whenever new data is received on the DCC
+ * channel. It indicates rvidcc_process() should be called at the next
+ * available opportunity (and also rvidcc_scaninput_for() if required). If
+ * using interrupts, schedule a 'bottom half' or tasklet to run. If not using
+ * interrupts, rvidcc_process() can be called directly from here.
+ */
+extern void rvidcc_cb_notify(void);
+
+#ifndef RVIDCC_RAW
+
+/* Network IP packet received callback.
+ *
+ * This is called from rvidcc_process() whenever an IP packet is received. Note:
+ * this only contains IP data without any Ethernet headers. The data must be
+ * copied and passed on to the OS appropriately.
+ */
+extern void rvidcc_cb_ip_packet_received(void *packet, size_t length);
+
+/* Pseudo ARP callback.
+ *
+ * This is called from rvidcc_process() whenever the ICE needs to determine if
+ * it should direct IP packets for the given IP address to this processor.
+ * Return non-zero if this is the case, or zero otherwise. The parameter
+ * passed is a pointer to 4-byte array which is the binary IP address in
+ * network (big-endian) order.
+ */
+extern int rvidcc_cb_has_addr(unsigned char *ip_binary);
+
+/* Set Ethernet MAC address callback.
+ *
+ * This is called from rvidcc_process() whenever in response to _init_dcc()'s
+ * request to the ICE for a (globally unique) MAC address. This happens very
+ * soon after initialisation, and if a MAC is required, then the virtual
+ * Ethernet driver should not be considered fully up and running until this
+ * has been received. The parameter is a pointer to a 6-byte array which is
+ * the MAC address.
+ */
+extern void rvidcc_cb_set_mac_address(unsigned char *mac);
+
+#endif
+
+
+#endif // RVIDCC_INTERFACE_H
diff --git a/arch/arm/common/rvidcc_linux.c b/arch/arm/common/rvidcc_linux.c
new file mode 100644
index 000000000000..c07058314475
--- /dev/null
+++ b/arch/arm/common/rvidcc_linux.c
@@ -0,0 +1,1014 @@
+/*
+ Copyright (C) 2004-2007 ARM Limited.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file does not
+ by itself cause the resulting work to be covered by the GNU General Public
+ License. However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based on
+ this file might be covered by the GNU General Public License.
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <net/route.h>
+#include <asm/hardware/rvidcc.h>
+
+#ifdef CONFIG_DEBUG_DCC_KGDB
+#include <linux/kgdb.h>
+#endif
+
+#include "rvidcc_config.h"
+#include "rvidcc_interface.h"
+
+#define ARM_DCC_VER "1.0"
+#define ARM_TTY_NAME "ttyDCC"
+#define ARM_ETH_NAME "ethDCC"
+#define ARM_DCC_MAJOR 204
+#define ARM_DCC_MINOR 46
+#define ARM_DCC_POLL_PERIOD 1 /* jiffies per poll: used in timed polled (non-interrupt) mode */
+
+/* SMP not supported */
+#ifdef CONFIG_SMP
+#error DCC module does not support SMP
+#endif
+
+/* Interrupt defininitons for known achitectures that have them */
+#ifdef CONFIG_ARCH_INTEGRATOR
+
+#define DCC_RX_IRQ IRQ_CM_COMMRX
+#define DCC_TX_IRQ IRQ_CM_COMMTX
+
+#elif defined(CONFIG_ARCH_L7200)
+
+#define DCC_RX_IRQ IRQ_DEBUG_RX
+#define DCC_TX_IRQ IRQ_DEBUG_TX
+
+#elif defined(CONFIG_ARCH_LH7A404)
+
+#define DCC_RX_IRQ IRQ_COMMRX
+#define DCC_TX_IRQ IRQ_COMMTX
+
+#elif defined(CONFIG_ARCH_VERSATILE_PB)
+
+#define DCC_RX_IRQ IRQ_COMMRx
+#define DCC_TX_IRQ IRQ_COMMTx
+
+#else
+
+#define DCC_RX_IRQ 0
+#define DCC_TX_IRQ 0
+
+#endif
+
+/* This section contains the primary OS driver functions and definitions */
+
+/* Structure containing our internal state, etc. */
+
+struct dccconfig dcc_config =
+{
+ .rx_interrupt = DCC_RX_IRQ,
+ .tx_interrupt = DCC_TX_IRQ,
+ .use_timer_poll = 1, /* use timer poll until interrupts are enabled (if ever) */
+ .timer_poll_period = ARM_DCC_POLL_PERIOD
+};
+
+struct dccinfo
+{
+ struct tty_struct *tty;
+ int tty_opens;
+ int init_called;
+ int kernel_in_panic;
+ volatile unsigned long timerpoll_lock;
+ volatile unsigned long tx_locked;
+#ifndef CONFIG_DEBUG_DCC_RAW
+ struct net_device *netdev;
+ char mac_address[ETH_ALEN];
+ struct sk_buff *pending_skb;
+#endif
+};
+static struct dccinfo dcc_info;
+
+/* Module parameters - IRQ's etc. an be set on the boot line */
+module_param_named(rxirq, dcc_config.rx_interrupt, uint, 0444);
+module_param_named(txirq, dcc_config.tx_interrupt, uint, 0444);
+module_param_named(pollperiod, dcc_config.timer_poll_period, ulong, 0444);
+MODULE_PARM_DESC(rxirq, "DCC receive IRQ number");
+MODULE_PARM_DESC(txirq, "DCC transmit IRQ number");
+MODULE_PARM_DESC(pollperiod, "DCC timer polling period");
+
+/* Tasklet used as a "bottom half" - services data collected by interrupt or timed poll */
+static void dcc_tasklet_action(unsigned long data);
+static DECLARE_TASKLET(dcc_tasklet, dcc_tasklet_action, 0);
+static void dcc_poll(void);
+
+/*
+ * Write data on the serial channel if no other write is in progress
+ */
+static size_t dcc_write_serial(const void *ptr, size_t len)
+{
+ size_t res = 0;
+
+ if (!test_and_set_bit(0, &dcc_info.tx_locked))
+ {
+ res = rvidcc_write_serial(ptr, len);
+ clear_bit(0, &dcc_info.tx_locked);
+ }
+
+ return res;
+}
+
+#ifndef RVIDCC_RAW
+/*
+ * Send a network packet if no other write is in progress
+ */
+static int dcc_transmit_ip_packet(void *packet, size_t length)
+{
+ int res = 0;
+
+ if (!test_and_set_bit(0, &dcc_info.tx_locked))
+ {
+ res = rvidcc_transmit_ip_packet(packet, length);
+ clear_bit(0, &dcc_info.tx_locked);
+ }
+
+ return res;
+}
+#endif
+
+/* KGDB support
+ *
+ * KGDB and the console/tty channel are mutually exclusive,
+ * i.e. KGDB takes over the tty channel if it is enabled.
+ */
+#ifdef CONFIG_DEBUG_DCC_KGDB
+
+#define KGDB_BUF_SIZE 1024 /* needs to be big enough to hold one GDB packet */
+static int dcc_init_dcc(void);
+static void dcc_print_banner(void);
+static void dcc_tasklet_action(unsigned long data);
+
+static char kgdb_buf[KGDB_BUF_SIZE];
+static size_t kgdb_buf_chars = 0;
+
+/* KGDB getchar routine */
+static int kgdb_getDebugChar(void)
+{
+ char ch;
+
+ /* The rest of the system is frozen at this point, so this is all that is running */
+ while (!rvidcc_read_serial(&ch, 1))
+ {
+ rvidcc_poll();
+ dcc_tasklet_action(1);
+ }
+
+ return (int)ch;
+}
+
+/* KGDB flush routine - ensures each GDB packet is sent as one message (more efficient) */
+static void kgdb_flushDebugChar(void)
+{
+ size_t written = 0;
+
+ /* The rest of the system is frozen at this point, so this is all that is running */
+ while (written < kgdb_buf_chars)
+ {
+ written += dcc_write_serial(&kgdb_buf[written], kgdb_buf_chars - written);
+ rvidcc_poll();
+ dcc_tasklet_action(1);
+ }
+
+ kgdb_buf_chars = 0;
+}
+
+/* KGDB putchar routine */
+static void kgdb_putDebugChar(int chr)
+{
+ kgdb_buf[kgdb_buf_chars++] = (char)chr;
+ if (kgdb_buf_chars >= KGDB_BUF_SIZE)
+ kgdb_flushDebugChar();
+}
+
+/* KGDB initialisation routine - can be called very early in kernel startup */
+static int init_kgdbDcc(void)
+{
+ int err = 0;
+ if (!dcc_info.init_called)
+ {
+ dcc_print_banner();
+ err = dcc_init_dcc();
+ if (!err)
+ printk(KERN_INFO "kgdb: debugging over DCC enabled\n");
+ }
+
+ return err;
+}
+
+/* KGDB device driver structure - only one of these is allowed globally */
+struct kgdb_io kgdb_io_ops =
+{
+ .read_char = kgdb_getDebugChar,
+ .write_char = kgdb_putDebugChar,
+ .init = init_kgdbDcc,
+ .flush = kgdb_flushDebugChar
+};
+
+#else
+
+/* TTY device driver routines. Must peacefully co-exist with console support.
+ *
+ * Not present when KGDB is enabled. KGDB has its own driver format (above).
+ */
+/* TTY device open routine */
+static int dcc_chr_open(struct tty_struct *tty, struct file *filp)
+{
+ if (!dcc_info.tty_opens++)
+ dcc_info.tty = tty;
+
+ return 0;
+}
+
+/* TTY device close routine */
+static void dcc_chr_close(struct tty_struct *tty, struct file *filp)
+{
+ if (!--dcc_info.tty_opens)
+ dcc_info.tty = NULL;
+}
+
+/* TTY device write routine */
+static int dcc_chr_write(struct tty_struct * tty,
+ const unsigned char *buf, int count)
+{
+ int bytes = 0;
+
+ if (count == 0)
+ return 0;
+
+ bytes = (int)dcc_write_serial(buf, count);
+
+ if (dcc_config.use_timer_poll)
+ dcc_poll();
+
+ return bytes;
+}
+
+/* TTY device routine to determine space left in output buffer */
+static int dcc_chr_write_room(struct tty_struct *tty)
+{
+ int space;
+
+ if (dcc_config.use_timer_poll)
+ dcc_poll();
+
+ space = rvidcc_serial_can_write() - 4 ; /* Leave 1 word spare for sentinel*/
+ return space > 0 ? space : 0;
+}
+
+/* TTY device routine to determine number of chars waiting in input buffer */
+static int dcc_chr_chars_in_buffer(struct tty_struct *tty)
+{
+ if (dcc_config.use_timer_poll)
+ dcc_poll();
+
+ return rvidcc_serial_can_read();
+}
+
+/* TTY device ioctl routine. Global and affects virtual Ethernet as well */
+static int dcc_chr_ioctl(struct tty_struct *tty, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret_val = 0;
+
+ switch (cmd) {
+ case DCC_SETPOLLPERIOD:
+ dcc_config.timer_poll_period = arg;
+ break;
+
+ case DCC_GETPOLLPERIOD:
+ ret_val = dcc_config.timer_poll_period;
+ break;
+
+ default:
+ ret_val = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret_val;
+}
+
+#endif /* CONFIG_DEBUG_DCC_KGDB */
+
+/* Network (virtual Ethernet over DCC) device driver routines
+ *
+ * Co-exists with KGDB, and will run when KGDB is at a breakpoint.
+ * Developer beware !
+ */
+#ifndef CONFIG_DEBUG_DCC_RAW
+
+/* Network device driver structure */
+static struct net_device* dcc_netdev;
+
+/* Callback from the universal DCC driver when a MAC address arrives from the RVI */
+void rvidcc_cb_set_mac_address(unsigned char *mac)
+{
+ memcpy(dcc_info.mac_address, mac, ETH_ALEN);
+
+ printk(KERN_INFO "DCC: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", dcc_info.mac_address[0],
+ dcc_info.mac_address[1], dcc_info.mac_address[2], dcc_info.mac_address[3],
+ dcc_info.mac_address[4], dcc_info.mac_address[5]);
+}
+
+
+/* Network device address validation */
+static int dcc_net_validate_addr(struct net_device *dev)
+{
+ /* Wait for the MAC address from the RVI */
+ unsigned long startjif = jiffies;
+ while (dcc_info.mac_address[0] == 0 &&
+ dcc_info.mac_address[1] == 0 &&
+ dcc_info.mac_address[2] == 0 &&
+ dcc_info.mac_address[3] == 0 &&
+ dcc_info.mac_address[4] == 0 &&
+ dcc_info.mac_address[5] == 0)
+ {
+ if (dcc_config.use_timer_poll)
+ dcc_poll();
+
+ /* Wait for a maximum of 1/2 a second */
+ if (startjif - jiffies > HZ/2)
+ {
+ printk(KERN_ERR "DCC: Virtual ethernet timed out waiting for MAC address\n");
+ break;
+ }
+ schedule();
+ }
+
+ memcpy(dev->dev_addr, dcc_info.mac_address, ETH_ALEN);
+
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Network device open routine */
+static int dcc_net_open(struct net_device *dev)
+{
+ netif_start_queue(dev);
+ dcc_info.netdev = dev; /* mark as running */
+ return 0;
+}
+
+/* Network device close routine */
+static int dcc_net_close(struct net_device *dev)
+{
+ /* Discard any pending TX packet */
+ if (dcc_info.pending_skb)
+ {
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(dcc_info.pending_skb);
+ dcc_info.pending_skb = NULL;
+ }
+
+ /* Mark as not running, to discard incoming packets */
+ dcc_info.netdev = NULL;
+
+ netif_stop_queue(dev);
+ return 0;
+}
+
+/* Called by universal driver when an IP packet is received */
+void rvidcc_cb_ip_packet_received(void *packet, size_t length)
+{
+ /* Drop the packet if the device isn't open */
+ if (dcc_info.netdev)
+ {
+ struct sk_buff *skb = dev_alloc_skb(length + 16);
+ struct ethhdr *buf;
+
+ if (!skb)
+ {
+ dcc_info.netdev->stats.rx_dropped++;
+ return;
+ }
+
+ /* Create Ethernet header */
+ skb_reserve(skb,2); /* Force 16 byte alignment */
+ buf = (struct ethhdr*)skb_put(skb, length + 14);
+ memcpy(buf->h_dest, dcc_info.mac_address, 6);
+ memcpy(&buf->h_source[3], &dcc_info.mac_address[3], 3);
+ buf->h_source[0] = 0x00;
+ buf->h_source[1] = 0x02;
+ buf->h_source[2] = 0xf7; /* RVI MAC address */
+ buf->h_proto = htons(ETH_P_IP);
+
+ /* Fill in the rest of the data */
+ memcpy((char*)buf + sizeof(struct ethhdr), packet, length);
+ skb->dev = dcc_info.netdev;
+ skb->protocol = eth_type_trans(skb, dcc_info.netdev);
+ dcc_info.netdev->stats.rx_packets++;
+ dcc_info.netdev->stats.rx_bytes += length+14;
+ netif_rx(skb);
+ }
+}
+
+/* Network device packet transmit routine */
+static int dcc_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ switch (ntohs(((struct ethhdr*)skb->data)->h_proto))
+ {
+ case ETH_P_ARP: /* ARP protocol */
+ {
+ struct sk_buff *skbreply = dev_alloc_skb(skb->len);
+ struct ethhdr *buf;
+ struct arphdr *arp;
+ unsigned char *arpdata, *origarpdata;
+
+ if (!skbreply)
+ {
+ dcc_info.netdev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ /* Set up manufactured ARP reply data */
+ buf = (struct ethhdr*)skb_put(skbreply, skb->len);
+ arp = (struct arphdr*)((char*)buf + sizeof(struct ethhdr));
+ arpdata = (unsigned char*)((char*)arp + sizeof(struct arphdr));
+ origarpdata = skb->data + sizeof(struct ethhdr) + sizeof(struct arphdr);
+ memcpy(buf, skb->data, skb->len);
+ memcpy(buf->h_dest, dcc_info.mac_address, 6);
+ memcpy(&buf->h_source[3], &dcc_info.mac_address[3], 3);
+ buf->h_source[0] = 0x00;
+ buf->h_source[1] = 0x02;
+ buf->h_source[2] = 0xf7; /* RVI MAC address */
+ arp->ar_op = htons(ARPOP_REPLY);
+ memcpy(&arpdata[0], buf->h_source, ETH_ALEN);
+ memcpy(&arpdata[10], buf->h_dest, ETH_ALEN);
+ memcpy(&arpdata[6], &origarpdata[16], 4);
+ memcpy(&arpdata[16], &origarpdata[6], 4);
+
+ skbreply->dev = dcc_info.netdev;
+ skbreply->protocol = eth_type_trans(skbreply, dcc_info.netdev);
+ dcc_info.netdev->stats.rx_packets++;
+ dcc_info.netdev->stats.rx_bytes += skb->len;
+ dcc_info.netdev->stats.tx_packets++;
+ dcc_info.netdev->stats.tx_bytes += skb->len;
+ dev_kfree_skb(skb);
+ netif_rx(skbreply);
+ break;
+ }
+ case ETH_P_IP: /* IP protocol */
+ {
+ if (dcc_transmit_ip_packet(&skb->data[14], skb->len-14)) /* discard eth header */
+ {
+ dcc_info.netdev->stats.tx_packets++;
+ dcc_info.netdev->stats.tx_bytes += skb->len;
+ dev_kfree_skb(skb);
+ }
+ else
+ {
+ dcc_info.pending_skb = skb;
+ netif_stop_queue(dev);
+ }
+
+ if (dcc_config.use_timer_poll)
+ dcc_poll();
+
+ break;
+ }
+ default:
+ printk(KERN_WARNING "DCC: dropping packet ethertype 0x%04x\n",
+ (int)ntohs(((struct ethhdr*)skb->data)->h_proto));
+ dcc_info.netdev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ }
+
+ return 0;
+}
+
+/* Universal driver callback to handle pseudo-ARP */
+int rvidcc_cb_has_addr(unsigned char *ip_binary)
+{
+ u32 ip;
+ memcpy(&ip, ip_binary, 4);
+
+ if (!dcc_info.netdev || IN_LOOPBACK(ip) || IN_MULTICAST(ip))
+ return 0;
+
+ /* Return 1 if address is local to the target */
+ return inet_addr_type(dev_net(dcc_info.netdev), ip) == RTN_LOCAL ? 1 : 0;
+}
+
+/* Network device initialisation routine */
+static void dcc_net_init(struct net_device *dev)
+{
+ /* Like normal Ethernet, but with specific differences */
+ ether_setup(dev);
+ dev->tx_queue_len = 3;
+
+ /* Driver routines */
+ dev->validate_addr = dcc_net_validate_addr;
+ dev->open = dcc_net_open;
+ dev->stop = dcc_net_close;
+ dev->hard_start_xmit = dcc_net_xmit;
+}
+
+#endif /* !CONFIG_DEBUG_DCC_RAW */
+
+/* Data transfer handling functionality
+ *
+ * We support interrupt and timer polled functionality
+ * if interrupts are not available.
+ */
+static void dcc_timer_poll(unsigned long arg);
+
+static struct timer_list dcc_timer = {
+ function: dcc_timer_poll
+};
+
+/* Poll routine for when interrupts are not used */
+static void dcc_poll(void)
+{
+ if (!test_and_set_bit(0, &dcc_info.timerpoll_lock) &&
+ !dcc_info.kernel_in_panic)
+ {
+ rvidcc_poll();
+ clear_bit(0, &dcc_info.timerpoll_lock);
+ }
+}
+
+/* Self-recheduling timer poll routine */
+static void dcc_timer_poll(unsigned long arg)
+{
+ dcc_poll();
+ dcc_timer.expires = jiffies + dcc_config.timer_poll_period;
+ add_timer(&dcc_timer);
+}
+
+/* DCC interrupt handler */
+static irqreturn_t dcc_read_interrupt(int irq, void *devid)
+{
+ if (!dcc_info.kernel_in_panic)
+ rvidcc_read();
+ return IRQ_HANDLED;
+}
+
+/* DCC interrupt handler */
+static irqreturn_t dcc_write_interrupt(int irq, void *devid)
+{
+ if (!dcc_info.kernel_in_panic)
+ rvidcc_write();
+ return IRQ_HANDLED;
+}
+
+/* Routine to process incoming DCC data from interrupt or timer poll */
+static void dcc_tasklet_action(unsigned long data)
+{
+#ifndef CONFIG_DEBUG_DCC_RAW
+ rvidcc_process();
+
+ /* Try to transmit any pending packet */
+ if (dcc_info.pending_skb && dcc_info.netdev)
+ {
+ if (dcc_transmit_ip_packet(&dcc_info.pending_skb->data[14], dcc_info.pending_skb->len-14))
+ {
+ dcc_info.netdev->stats.tx_packets++;
+ dcc_info.netdev->stats.tx_bytes += dcc_info.pending_skb->len;
+ dev_kfree_skb(dcc_info.pending_skb);
+ dcc_info.pending_skb = NULL;
+ netif_wake_queue(dcc_info.netdev);
+ }
+ }
+#endif
+
+ /* tasklet can only run on one CPU at a time and this is the only place
+ * we do a serial read, so no locking needed here */
+#ifdef CONFIG_DEBUG_DCC_KGDB
+ if (data != 1 && rvidcc_serial_can_read())
+ {
+ /* Absorb ^C before triggering a hardcoded breakpoint */
+ if (rvidcc_scan_input_for(0x03, 1))
+ {
+ char buf;
+ rvidcc_read_serial(&buf, 1);
+ }
+ breakpoint();
+ }
+#else
+ /* Receive any bytes that may be pending if the device has been opened */
+ if (dcc_info.tty)
+ {
+ size_t data_available = rvidcc_serial_can_read();
+ if (data_available)
+ {
+ unsigned char* buf;
+ int len = tty_prepare_flip_string(dcc_info.tty, &buf, data_available);
+ if (len)
+ {
+ rvidcc_read_serial(buf, len);
+ tty_flip_buffer_push(dcc_info.tty);
+ }
+ }
+ }
+#endif
+}
+
+/* Universal driver callback called when data has arrived on DCC */
+void rvidcc_cb_notify()
+{
+ tasklet_schedule(&dcc_tasklet);
+}
+
+/* Universal initialisation - ensures init only happens once */
+static int dcc_init_dcc(void)
+{
+ int err = 0;
+ if (!dcc_info.init_called)
+ {
+ err = rvidcc_init();
+ if (err == 0)
+ dcc_info.init_called = 1;
+ else
+ return -ENODEV;
+ }
+
+ return err;
+}
+
+/* Banner to be printed on initialisation */
+static void dcc_print_banner(void)
+{
+ printk(KERN_INFO "RealView ICE DCC device driver %s "
+#ifdef CONFIG_DEBUG_DCC_RAW
+ "[raw mode] "
+#else
+ "[tty_eth mode] "
+#endif
+ "(C)2004-2007 ARM Limited\n", ARM_DCC_VER);
+}
+
+static void dcc_drain_outbuf(void)
+{
+ size_t bytesPending;
+ size_t lastBytesPending = 0;
+ int failcount = 0;
+
+ while ((bytesPending = rvidcc_outbuf_data()) > 0)
+ {
+ if (bytesPending >= lastBytesPending)
+ ++failcount;
+
+ if (failcount > 10)
+ {
+ /* The queue isn't draining: either the connection to the RVI is
+ * lost or we can't process messages fast enough. Either way, it's
+ * bad to block forever, so bail out */
+ break;
+ }
+
+ lastBytesPending = bytesPending;
+
+ rvidcc_poll();
+ }
+}
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+
+/* TTY device driver structure */
+static const struct tty_operations dcc_tty_ops =
+{
+ .open = dcc_chr_open,
+ .close = dcc_chr_close,
+ .write = dcc_chr_write,
+ .write_room = dcc_chr_write_room,
+ .chars_in_buffer = dcc_chr_chars_in_buffer,
+ .ioctl = dcc_chr_ioctl
+};
+
+static struct tty_driver *dcc_tty_driver;
+
+/* Create and install TTY driver */
+static int dcc_init_tty_driver(void)
+{
+ int error = 0;
+
+ dcc_tty_driver = alloc_tty_driver(1);
+ if (!dcc_tty_driver)
+ return -ENOMEM;
+ dcc_tty_driver->owner = THIS_MODULE;
+ dcc_tty_driver->driver_name = ARM_TTY_NAME;
+ dcc_tty_driver->name = ARM_TTY_NAME;
+ dcc_tty_driver->major = ARM_DCC_MAJOR;
+ dcc_tty_driver->minor_start = ARM_DCC_MINOR;
+ dcc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ dcc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ dcc_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ dcc_tty_driver->init_termios = tty_std_termios;
+ tty_set_operations(dcc_tty_driver, &dcc_tty_ops);
+ if ((error = tty_register_driver(dcc_tty_driver)))
+ {
+ printk(KERN_ERR "DCC: Can't register tty device %d, error = %d\n",
+ ARM_DCC_MINOR, error);
+ put_tty_driver(dcc_tty_driver);
+ dcc_tty_driver = NULL;
+ return error;
+ }
+ return 0;
+}
+
+/* Console device print routine */
+static void dcc_console_print(struct console *co, const char *buf, unsigned count)
+{
+ unsigned int bytes = 0;
+
+ /* Send message out */
+ bytes = (unsigned int)dcc_write_serial(buf, count);
+
+ /* If buffer is full stall the system until there is space */
+ /* A flood of printk's usually means the system is dying anyway */
+ if (bytes < count)
+ {
+ unsigned long flags;
+ local_irq_save(flags);
+
+ while (bytes < count)
+ {
+ rvidcc_poll();
+ bytes += (unsigned int)dcc_write_serial(buf + bytes, count - bytes);
+ }
+
+ local_irq_restore(flags);
+ }
+
+ /* Do an immediate flush if kernel has panicked */
+ if (dcc_info.kernel_in_panic)
+ {
+ unsigned long flags;
+ local_irq_save(flags);
+
+ dcc_drain_outbuf();
+
+ local_irq_restore(flags);
+ }
+}
+
+/* Console device initialisation routine */
+static struct tty_driver* dcc_console_device(struct console *co, int *index)
+{
+ *index = 0;
+ return dcc_tty_driver;
+}
+
+/* Console device driver */
+static struct console dcc_con_driver =
+{
+ .name = ARM_TTY_NAME,
+ .write = dcc_console_print,
+ .device = dcc_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+
+/* Routine to ensure DCC is flushed on reboot or kernel panic */
+static int dcc_reboot_handler(struct notifier_block *this,
+ unsigned long event, void *unused)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+
+ dcc_drain_outbuf();
+
+ local_irq_restore(flags);
+
+ return NOTIFY_OK;
+}
+
+/* Reboot notifier structure */
+static struct notifier_block dcc_reboot_notifier =
+{
+ dcc_reboot_handler,
+ NULL,
+ 0
+};
+
+/* Called when kernel enters the panic state */
+static int dcc_panic_handler(struct notifier_block *this,
+ unsigned long event, void *unused)
+{
+ dcc_info.kernel_in_panic = 1;
+ return dcc_reboot_handler(this, event, unused);
+}
+
+/* Panic notifier structure */
+static struct notifier_block dcc_panic_notifier =
+{
+ .notifier_call = dcc_panic_handler,
+ .next = NULL,
+ .priority = 0
+};
+
+/* Early console initialization. Preceeds driver initialization. */
+static int __init dcc_console_init(void)
+{
+ int err = 0;
+
+ if (!dcc_info.init_called)
+ {
+ dcc_print_banner();
+ err = dcc_init_dcc();
+ }
+
+ if (!err)
+ {
+ register_reboot_notifier(&dcc_reboot_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list, &dcc_panic_notifier);
+ register_console(&dcc_con_driver);
+ }
+
+ return err;
+}
+#endif /* !CONFIG_DEBUG_DCC_KGDB */
+
+/* Primary module (and devices) initialisation routine */
+int __init dcc_init(void)
+{
+ int ret = 0;
+
+ if (!dcc_info.init_called)
+ dcc_print_banner();
+
+ /* Detect whether timer polling when required */
+ if (dcc_config.rx_interrupt == dcc_config.tx_interrupt)
+ {
+ dcc_config.use_timer_poll = 1;
+
+ if (dcc_config.rx_interrupt != 0)
+ printk(KERN_ERR "DCC: IRQ numbers must be different for Rx and Tx !!!!!\n");
+ }
+ else
+ dcc_config.use_timer_poll = 0;
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+ ret = dcc_init_tty_driver();
+#endif
+
+#ifndef CONFIG_DEBUG_DCC_RAW
+ if (!ret)
+ {
+ /* Install network device driver */
+ dcc_netdev = alloc_netdev(0, ARM_ETH_NAME, dcc_net_init);
+ if (dcc_netdev == NULL)
+ {
+ printk(KERN_ERR "DCC: Can't allocate net device\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+ else
+ {
+ ret = register_netdev(dcc_netdev);
+
+ if (ret)
+ {
+ printk(KERN_ERR "DCC: Can't register net device\n");
+ free_netdev(dcc_netdev);
+ goto error;
+ }
+ }
+ }
+#endif
+
+ /* Initiate interrupts or timer polling as necessary */
+ if (!ret)
+ {
+ if (!dcc_config.use_timer_poll)
+ {
+ ret = dcc_init_dcc();
+
+ if (ret)
+ {
+ goto error;
+ }
+ else
+ {
+ if (request_irq(dcc_config.rx_interrupt, dcc_read_interrupt, 0, "dcc:rx", NULL) ||
+ request_irq(dcc_config.tx_interrupt, dcc_write_interrupt, 0, "dcc:tx", NULL))
+ {
+ printk(KERN_ERR "DCC: Can't install interrupt handlers for IRQ%u and/or IRQ%u\n",
+ dcc_config.rx_interrupt, dcc_config.tx_interrupt);
+ /* unregister tty & netdev drivers on error */
+ ret = -EBUSY;
+ goto error;
+ }
+ else
+ printk(KERN_INFO "DCC: Using IRQ%u (Rx) and IRQ%u (Tx)\n",
+ dcc_config.rx_interrupt, dcc_config.tx_interrupt);
+ }
+ }
+ else
+ {
+ init_timer(&dcc_timer);
+ printk(KERN_INFO "DCC: Using timer polled mode\n");
+
+ ret = dcc_init_dcc();
+ if (ret)
+ {
+ del_timer_sync(&dcc_timer);
+ goto error;
+ }
+ else
+ {
+ dcc_timer.expires = jiffies + dcc_config.timer_poll_period;
+ add_timer(&dcc_timer);
+ }
+ }
+ }
+
+ return ret;
+
+error:
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+ if (dcc_tty_driver)
+ {
+ tty_unregister_driver(dcc_tty_driver);
+ put_tty_driver(dcc_tty_driver);
+ dcc_tty_driver = NULL;
+ }
+#endif
+
+#ifndef CONFIG_DEBUG_DCC_RAW
+ if (dcc_netdev)
+ {
+ unregister_netdev(dcc_netdev);
+ free_netdev(dcc_netdev);
+ dcc_netdev = NULL;
+ }
+#endif
+
+ return ret;
+}
+
+/* Module cleanup (exit) routine - only called if compiled as a module */
+void __exit dcc_cleanup(void)
+{
+ if (!dcc_config.use_timer_poll)
+ {
+ free_irq(dcc_config.rx_interrupt, NULL);
+ free_irq(dcc_config.tx_interrupt, NULL);
+ }
+ else
+ del_timer_sync(&dcc_timer);
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+ tty_unregister_driver(dcc_tty_driver);
+ put_tty_driver(dcc_tty_driver);
+#endif
+
+#ifndef CONFIG_DEBUG_DCC_RAW
+ unregister_netdev(dcc_netdev);
+ free_netdev(dcc_netdev);
+#endif
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+ unregister_console(&dcc_con_driver);
+ unregister_reboot_notifier(&dcc_reboot_notifier);
+ atomic_notifier_chain_unregister(&panic_notifier_list, &dcc_panic_notifier);
+#endif
+
+ dcc_drain_outbuf();
+}
+
+#ifndef CONFIG_DEBUG_DCC_KGDB
+console_initcall(dcc_console_init);
+#endif
+module_init(dcc_init);
+module_exit(dcc_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ARM Ltd");
+MODULE_DESCRIPTION("Driver for the ARM Debug Communications Channel");
+MODULE_SUPPORTED_DEVICE(ARM_TTY_NAME);
diff --git a/arch/arm/configs/realview-nommu_defconfig b/arch/arm/configs/realview-nommu_defconfig
new file mode 100644
index 000000000000..71596a53e6ac
--- /dev/null
+++ b/arch/arm/configs/realview-nommu_defconfig
@@ -0,0 +1,1373 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28
+# Thu Feb 5 12:10:15 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0x00000000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+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_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_MMU is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_REALVIEW=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# RealView platform type
+#
+CONFIG_MACH_REALVIEW_EB=y
+# CONFIG_REALVIEW_EB_A9MP is not set
+CONFIG_REALVIEW_EB_ARM11MP=y
+# CONFIG_REALVIEW_EB_ARM11MP_REVB is not set
+CONFIG_MACH_REALVIEW_PB11MP=y
+CONFIG_MACH_REALVIEW_PB1176=y
+# CONFIG_MACH_REALVIEW_PBA8 is not set
+CONFIG_MACH_REALVIEW_PBX=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_ARM7TDMI is not set
+# CONFIG_CPU_ARM9TDMI is not set
+# CONFIG_CPU_ARM926T is not set
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+# CONFIG_CPU_V7 is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_HIGH_VECTOR is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_TLS_REG_EMUL=y
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x00000000
+CONFIG_DRAM_SIZE=0x10000000
+CONFIG_FLASH_MEM_BASE=0x40000000
+CONFIG_FLASH_SIZE=0x04000000
+CONFIG_ARM_GIC=y
+CONFIG_ICST307=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_SMP is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_ARM_ASM_UNIFIED is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+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_XFRM_STATISTICS 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=y
+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_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_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_NET_DSA 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_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# 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=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_ARM_INTEGRATOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
+# 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 is not set
+
+#
+# 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 is not set
+# 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_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_MV is not set
+CONFIG_HAVE_PATA_PLATFORM=y
+CONFIG_PATA_PLATFORM=y
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# 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_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_SMC911X=y
+# 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP 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
+
+#
+# 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=y
+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=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY 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_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+CONFIG_I2C_VERSATILE=y
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 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
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# 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_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# 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_ARMCLCD=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+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 is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_ARMAACI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_BRIGHT=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DELL=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_ISP1760_HCD=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+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_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG 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_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_ARMMMCI=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+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_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# 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_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+# 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_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 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 is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# 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 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_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# 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_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# 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_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_CONSOLE=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig
index 7e253f58ed18..907e54344dad 100644
--- a/arch/arm/configs/realview_defconfig
+++ b/arch/arm/configs/realview_defconfig
@@ -1,204 +1,105 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28-rc2
-# Mon Nov 10 14:39:48 2008
+# Linux kernel version: 2.6.14-rc2
+# Thu Sep 29 14:50:10 2005
#
CONFIG_ARM=y
-CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-# CONFIG_GENERIC_GPIO is not set
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_HAVE_LATENCYTOP_SUPPORT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_VECTORS_BASE=0xffff0000
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# General setup
+# Code maturity level options
#
-CONFIG_EXPERIMENTAL=y
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
+CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
-# CONFIG_GROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-# CONFIG_RELAY is not set
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
+CONFIG_INITRAMFS_SOURCE=""
# CONFIG_EMBEDDED is not set
-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_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_CLK=y
-CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
-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
-# CONFIG_BLK_DEV_INTEGRITY is not set
#
-# IO Schedulers
+# Loadable module support
#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
-CONFIG_DEFAULT_DEADLINE=y
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="deadline"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_FREEZER is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
#
# System Type
#
-# CONFIG_ARCH_AAEC2000 is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_REALVIEW=y
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_NETX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IOP32X is not set
-# CONFIG_ARCH_IOP33X is not set
-# CONFIG_ARCH_IXP23XX is not set
-# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_LOKI is not set
-# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_ORION5X is not set
-# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_REALVIEW=y
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
#
# RealView platform type
#
CONFIG_MACH_REALVIEW_EB=y
-# CONFIG_REALVIEW_EB_A9MP is not set
-CONFIG_REALVIEW_EB_ARM11MP=y
-# CONFIG_REALVIEW_EB_ARM11MP_REVB is not set
-CONFIG_MACH_REALVIEW_PB11MP=y
-CONFIG_MACH_REALVIEW_PB1176=y
-# CONFIG_MACH_REALVIEW_PBA8 is not set
#
# Processor Type
#
CONFIG_CPU_32=y
-# CONFIG_CPU_ARM926T is not set
-CONFIG_CPU_V6=y
-# CONFIG_CPU_32v6K is not set
-# CONFIG_CPU_V7 is not set
-CONFIG_CPU_32v6=y
-CONFIG_CPU_ABRT_EV6=y
-CONFIG_CPU_PABRT_NOIFAR=y
-CONFIG_CPU_CACHE_V6=y
-CONFIG_CPU_CACHE_VIPT=y
-CONFIG_CPU_COPY_V6=y
-CONFIG_CPU_TLB_V6=y
-CONFIG_CPU_HAS_ASID=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_ARM926T=y
+# CONFIG_CPU_V6 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
#
# Processor Features
@@ -206,9 +107,8 @@ CONFIG_CPU_CP15_MMU=y
CONFIG_ARM_THUMB=y
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_BPREDICT_DISABLE is not set
-CONFIG_OUTER_CACHE=y
-CONFIG_CACHE_L2X0=y
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
CONFIG_ARM_GIC=y
CONFIG_ICST307=y
@@ -216,41 +116,20 @@ CONFIG_ICST307=y
# Bus support
#
CONFIG_ARM_AMBA=y
-# CONFIG_PCI_SYSCALL is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
# CONFIG_PCCARD is not set
#
# Kernel Features
#
-# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_SMP is not set
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
-# CONFIG_PREEMPT is not set
-CONFIG_HZ=100
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
-# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-# CONFIG_PHYS_ADDR_T_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=0
-CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
+# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_ALIGNMENT_TRAP=y
#
@@ -260,12 +139,6 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# CPU Power Management
-#
-# CONFIG_CPU_IDLE is not set
#
# Floating point emulation
@@ -274,24 +147,26 @@ CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=tt
#
# At least one emulation must be selected
#
-# CONFIG_FPE_NWFPE is not set
-# CONFIG_FPE_FASTFPE is not set
-CONFIG_VFP=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_VFP is not set
#
# Userspace binary formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_HAVE_AOUT=y
# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
#
# Power management options
#
# CONFIG_PM is not set
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
CONFIG_NET=y
#
@@ -300,11 +175,6 @@ CONFIG_NET=y
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_XFRM_STATISTICS is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -316,56 +186,34 @@ 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_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_TCP_CONG_BIC=y
# CONFIG_IPV6 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_NET_DSA 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
+# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-# CONFIG_WIRELESS is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -374,37 +222,30 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
#
# Generic Driver Options
#
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
+# 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
+
+#
+# Memory Technology Devices (MTD)
+#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
-# CONFIG_MTD_AR7_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
-# CONFIG_RFD_FTL is not set
-# CONFIG_SSFDC is not set
-# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
@@ -425,6 +266,7 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I8 is not set
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
@@ -437,6 +279,7 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
CONFIG_MTD_ARM_INTEGRATOR=y
+# CONFIG_MTD_EDB7312 is not set
# CONFIG_MTD_PLATRAM is not set
#
@@ -445,7 +288,7 @@ CONFIG_MTD_ARM_INTEGRATOR=y
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLOCK2MTD is not set
+# CONFIG_MTD_BLKMTD is not set
#
# Disk-On-Chip Device Drivers
@@ -453,81 +296,121 @@ CONFIG_MTD_ARM_INTEGRATOR=y
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_ONENAND is not set
#
-# UBI - Unsorted block images
+# Parallel port support
#
-# CONFIG_MTD_UBI is not set
# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
+
+#
+# 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_RAM_COUNT=16
# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
# CONFIG_ATA_OVER_ETH is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_NETLINK is not set
-# 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_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_VETH 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_SMC91X=y
# CONFIG_DM9000 is not set
-CONFIG_SMC911X=y
-# 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
-# CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS 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_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
# CONFIG_ISDN is not set
#
# Input device support
#
CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -537,6 +420,7 @@ 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_EVBUG is not set
@@ -549,19 +433,11 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY 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_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
@@ -579,11 +455,8 @@ CONFIG_SERIO_LIBPS2=y
# Character devices
#
CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -602,91 +475,73 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=16
+
+#
+# IPMI
+#
# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
+# CONFIG_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
-# CONFIG_TCG_TPM is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
# CONFIG_I2C is not set
-# CONFIG_SPI is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
-# CONFIG_WATCHDOG is not set
#
-# Sonics Silicon Backplane
+# Hardware Monitoring support
#
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB is not set
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
#
-# Multifunction device drivers
+# Misc devices
#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_T7L66XB is not set
-# CONFIG_MFD_TC6387XB is not set
-# CONFIG_MFD_WM8400 is not set
#
-# Multimedia devices
+# Multimedia Capabilities Port drivers
#
#
-# Multimedia core support
+# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
#
-# Multimedia drivers
+# Digital Video Broadcasting Devices
#
-# CONFIG_DAB is not set
+# CONFIG_DVB is not set
#
# Graphics support
#
-# 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_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
-# 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_FOREIGN_ENDIAN is not set
-# CONFIG_FB_SYS_FOPS is not set
-# CONFIG_FB_SVGALIB is not set
+CONFIG_FB_SOFT_CURSOR=y
# 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_ARMCLCD=y
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_METRONOME is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
@@ -694,17 +549,27 @@ CONFIG_FB_ARMCLCD=y
# CONFIG_VGA_CONSOLE is not set
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 is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
+
+#
+# Advanced Linux Sound Architecture
+#
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
@@ -712,71 +577,59 @@ CONFIG_SND_PCM=y
CONFIG_SND_OSSEMUL=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
-CONFIG_SND_VMASTER=y
-CONFIG_SND_AC97_CODEC=y
-# CONFIG_SND_DRIVERS is not set
-CONFIG_SND_ARM=y
-CONFIG_SND_ARMAACI=y
-# CONFIG_SND_SOC is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_ARMAACI is not set
+
+#
+# Open Sound System
+#
# CONFIG_SOUND_PRIME is not set
-CONFIG_AC97_BUS=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-# CONFIG_MMC_DEBUG is not set
-# CONFIG_MMC_UNSAFE_RESUME is not set
#
-# MMC/SD/SDIO Card Drivers
+# USB support
#
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_BOUNCE=y
-# CONFIG_SDIO_UART is not set
-# CONFIG_MMC_TEST is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
#
-# MMC/SD/SDIO Host Controller Drivers
+# USB Gadget Support
#
-CONFIG_MMC_ARMMMCI=y
-# CONFIG_MMC_SDHCI is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_NEW_LEDS is not set
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
-# CONFIG_DMADEVICES is not set
+# CONFIG_USB_GADGET is not set
#
-# Voltage and Current regulators
+# MMC/SD Card support
#
-# CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
-# CONFIG_UIO is not set
+# CONFIG_MMC is not set
#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4_FS is not set
+# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
-# CONFIG_OCFS2_FS is not set
-CONFIG_DNOTIFY=y
+# 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
@@ -801,59 +654,51 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# Pseudo filesystems
#
CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
-# CONFIG_CONFIGFS_FS is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
CONFIG_CRAMFS=y
# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
+
+#
+# Network File Systems
+#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_ROOT_NFS=y
# 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_REGISTER_V4 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 is not set
CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
@@ -894,71 +739,26 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
-# CONFIG_DLM is not set
#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=1024
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_SLAB is not set
-# 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_WRITECOUNT is not set
-CONFIG_DEBUG_MEMORY_INIT=y
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_LATENCYTOP is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-CONFIG_NOP_TRACER=y
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
-# CONFIG_SAMPLES is not set
-CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_DEBUG_LL is not set
#
@@ -966,106 +766,21 @@ CONFIG_DEBUG_ERRORS=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
#
-# Compression
+# Cryptographic options
#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO is not set
#
-# Random Number Generation
+# Hardware crypto devices
#
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
#
# Library routines
#
-CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
-# CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig
index b11c5da3996c..8355f88f7292 100644
--- a/arch/arm/configs/versatile_defconfig
+++ b/arch/arm/configs/versatile_defconfig
@@ -611,7 +611,7 @@ CONFIG_I2C_ALGOBIT=y
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_DS1374 is not set
-CONFIG_EEPROM_LEGACY=m
+CONFIG_SENSORS_EEPROM=m
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 6116e4893c0a..2539d254caa7 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -96,7 +96,11 @@
* assumes FIQs are enabled, and that the processor is in SVC mode.
*/
.macro save_and_disable_irqs, oldcpsr
+#ifdef CONFIG_CPU_V7M
+ mrs \oldcpsr, primask
+#else
mrs \oldcpsr, cpsr
+#endif
disable_irq
.endm
@@ -105,7 +109,11 @@
* guarantee that this will preserve the flags.
*/
.macro restore_irqs, oldcpsr
+#ifdef CONFIG_CPU_V7M
+ msr primask, \oldcpsr
+#else
msr cpsr_c, \oldcpsr
+#endif
.endm
#define USER(x...) \
@@ -114,3 +122,90 @@
.align 3; \
.long 9999b,9001f; \
.previous
+
+#if defined(CONFIG_CPU_V7M)
+ .macro setmode, mode, reg
+ .endm
+#elif defined(CONFIG_THUMB2_KERNEL)
+ .macro setmode, mode, reg
+ mov \reg, #\mode
+ msr cpsr_c, \reg
+ .endm
+#else
+ .macro setmode, mode, reg
+ msr cpsr_c, #\mode
+ .endm
+#endif
+
+/*
+ * STRT/LDRT access macros with ARM and Thumb-2 variants
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+
+ .macro usraccoff, instr, reg, ptr, inc, off, cond, abort
+9999:
+ .if \inc == 1
+ \instr\cond\()bt \reg, [\ptr, #\off]
+ .elseif \inc == 4
+ \instr\cond\()t \reg, [\ptr, #\off]
+ .else
+ .error "Unsupported inc macro argument"
+ .endif
+
+ .section __ex_table,"a"
+ .align 3
+ .long 9999b, \abort
+ .previous
+ .endm
+
+ .macro usracc, instr, reg, ptr, inc, cond, rept, abort
+ @ explicit IT instruction needed because of the label
+ @ introduced by the USER macro
+ .ifnc \cond,al
+ .if \rept == 1
+ itt \cond
+ .elseif \rept == 2
+ ittt \cond
+ .else
+ .error "Unsupported rept macro argument"
+ .endif
+ .endif
+
+ @ Slightly optimised to avoid incrementing the pointer twice
+ usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
+ .if \rept == 2
+ usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort
+ .endif
+
+ add\cond \ptr, #\rept * \inc
+ .endm
+
+#else /* !CONFIG_THUMB2_KERNEL */
+
+ .macro usracc, instr, reg, ptr, inc, cond, rept, abort
+ .rept \rept
+9999:
+ .if \inc == 1
+ \instr\cond\()bt \reg, [\ptr], #\inc
+ .elseif \inc == 4
+ \instr\cond\()t \reg, [\ptr], #\inc
+ .else
+ .error "Unsupported inc macro argument"
+ .endif
+
+ .section __ex_table,"a"
+ .align 3
+ .long 9999b, \abort
+ .previous
+ .endr
+ .endm
+
+#endif /* !CONFIG_THUMB2_KERNEL */
+
+ .macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
+ usracc str, \reg, \ptr, \inc, \cond, \rept, \abort
+ .endm
+
+ .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
+ usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort
+ .endm
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index ee99723b3a6c..ce438d119a33 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -20,44 +20,49 @@
#ifdef __KERNEL__
#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) (((v)->counter) = (i))
#if __LINUX_ARM_ARCH__ >= 6
+#ifdef CONFIG_ARM_ERRATA_351422
+static inline int atomic_backoff_delay(void)
+{
+ unsigned int delay;
+ __asm__ __volatile__(
+ " mrc p15, 0, %0, c0, c0, 5\n"
+ " and %0, %0, #0xf\n"
+ " mov %0, %0, lsl #8\n"
+ "1: subs %0, %0, #1\n"
+ " bpl 1b\n"
+ : "=&r" (delay)
+ :
+ : "cc" );
+
+ return 1;
+}
+#else
+#define atomic_backoff_delay() 1
+#endif
+
/*
* ARMv6 UP and SMP safe atomic ops. We use load exclusive and
* store exclusive to ensure that these are atomic. We may loop
- * to ensure that the update happens. Writing to 'v->counter'
- * without using the following operations WILL break the atomic
- * nature of these ops.
+ * to ensure that the update happens.
*/
-static inline void atomic_set(atomic_t *v, int i)
-{
- unsigned long tmp;
-
- __asm__ __volatile__("@ atomic_set\n"
-"1: ldrex %0, [%1]\n"
-" strex %0, %2, [%1]\n"
-" teq %0, #0\n"
-" bne 1b"
- : "=&r" (tmp)
- : "r" (&v->counter), "r" (i)
- : "cc");
-}
-
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long tmp;
int result;
+ do {
__asm__ __volatile__("@ atomic_add_return\n"
"1: ldrex %0, [%2]\n"
" add %0, %0, %3\n"
" strex %1, %0, [%2]\n"
-" teq %1, #0\n"
-" bne 1b"
: "=&r" (result), "=&r" (tmp)
: "r" (&v->counter), "Ir" (i)
: "cc");
+ } while (tmp && atomic_backoff_delay());
return result;
}
@@ -67,15 +72,15 @@ static inline int atomic_sub_return(int i, atomic_t *v)
unsigned long tmp;
int result;
+ do {
__asm__ __volatile__("@ atomic_sub_return\n"
"1: ldrex %0, [%2]\n"
" sub %0, %0, %3\n"
" strex %1, %0, [%2]\n"
-" teq %1, #0\n"
-" bne 1b"
: "=&r" (result), "=&r" (tmp)
: "r" (&v->counter), "Ir" (i)
: "cc");
+ } while (tmp && atomic_backoff_delay());
return result;
}
@@ -89,11 +94,12 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
"ldrex %1, [%2]\n"
"mov %0, #0\n"
"teq %1, %3\n"
+ "it eq\n"
"strexeq %0, %4, [%2]\n"
: "=&r" (res), "=&r" (oldval)
: "r" (&ptr->counter), "Ir" (old), "r" (new)
: "cc");
- } while (res);
+ } while (res && atomic_backoff_delay());
return oldval;
}
@@ -102,15 +108,15 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
unsigned long tmp, tmp2;
+ do {
__asm__ __volatile__("@ atomic_clear_mask\n"
"1: ldrex %0, [%2]\n"
" bic %0, %0, %3\n"
" strex %1, %0, [%2]\n"
-" teq %1, #0\n"
-" bne 1b"
: "=&r" (tmp), "=&r" (tmp2)
: "r" (addr), "Ir" (mask)
: "cc");
+ } while (tmp && atomic_backoff_delay());
}
#else /* ARM_ARCH_6 */
@@ -121,8 +127,6 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
#error SMP not supported on pre-ARMv6 CPUs
#endif
-#define atomic_set(v,i) (((v)->counter) = (i))
-
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long flags;
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index a160e0a9035c..b753d915e4df 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -114,6 +114,14 @@
//# endif
#endif
+#if defined(CONFIG_CPU_V7M)
+# ifdef _CACHE
+# error "Multi-cache not supported on ARMv7-M"
+# else
+# define _CACHE v7m
+# endif
+#endif
+
#if !defined(_CACHE) && !defined(MULTI_CACHE)
#error Unknown cache maintainence model
#endif
@@ -234,6 +242,22 @@ extern struct cpu_cache_fns cpu_cache;
#else
+#ifdef CONFIG_CPU_V7M
+
+static inline void v7m_flush_kern_all(void) { }
+static inline void v7m_flush_user_all(void) { }
+static inline void v7m_flush_user_range(unsigned long a, unsigned long b, unsigned int c) { }
+
+static inline void v7m_coherent_kern_range(unsigned long a, unsigned long b) { }
+static inline void v7m_coherent_user_range(unsigned long a, unsigned long b) { }
+static inline void v7m_flush_kern_dcache_page(void *a) { }
+
+static inline void v7m_dma_inv_range(const void *a, const void *b) { }
+static inline void v7m_dma_clean_range(const void *a, const void *b) { }
+static inline void v7m_dma_flush_range(const void *a, const void *b) { }
+
+#endif
+
#define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all)
#define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all)
#define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range)
@@ -264,6 +288,22 @@ extern void dmac_flush_range(const void *, const void *);
#endif
+#ifdef CONFIG_CPU_NO_CACHE_BCAST
+enum smp_dma_cache_type {
+ SMP_DMA_CACHE_INV,
+ SMP_DMA_CACHE_CLEAN,
+ SMP_DMA_CACHE_FLUSH,
+};
+extern void smp_dma_cache_op(int type, const void *start, const void *end);
+#define smp_dma_inv_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_INV, s, e)
+#define smp_dma_clean_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_CLEAN, s, e)
+#define smp_dma_flush_range(s, e) smp_dma_cache_op(SMP_DMA_CACHE_FLUSH, s, e)
+#else
+#define smp_dma_inv_range dmac_inv_range
+#define smp_dma_clean_range dmac_clean_range
+#define smp_dma_flush_range dmac_flush_range
+#endif
+
#ifdef CONFIG_OUTER_CACHE
extern struct outer_cache_fns outer_cache;
diff --git a/arch/arm/include/asm/checksum.h b/arch/arm/include/asm/checksum.h
index 6dcc16430868..e4b9f6e17365 100644
--- a/arch/arm/include/asm/checksum.h
+++ b/arch/arm/include/asm/checksum.h
@@ -73,6 +73,7 @@ ip_fast_csum(const void *iph, unsigned int ihl)
1: adcs %0, %0, %3 \n\
ldr %3, [%1], #4 \n\
tst %2, #15 @ do this carefully \n\
+ it ne \n\
subne %2, %2, #1 @ without destroying \n\
bne 1b @ the carry flag \n\
adcs %0, %0, %3 \n\
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 7b9d27e749b8..c2fe374fcb7f 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -8,6 +8,21 @@
#define CPUID_TCM 2
#define CPUID_TLBTYPE 3
+#define CPUID_EXT_PFR0 "c1, 0"
+#define CPUID_EXT_PFR1 "c1, 1"
+#define CPUID_EXT_DFR0 "c1, 2"
+#define CPUID_EXT_AFR0 "c1, 3"
+#define CPUID_EXT_MMFR0 "c1, 4"
+#define CPUID_EXT_MMFR1 "c1, 5"
+#define CPUID_EXT_MMFR2 "c1, 6"
+#define CPUID_EXT_MMFR3 "c1, 7"
+#define CPUID_EXT_ISAR0 "c2, 0"
+#define CPUID_EXT_ISAR1 "c2, 1"
+#define CPUID_EXT_ISAR2 "c2, 2"
+#define CPUID_EXT_ISAR3 "c2, 3"
+#define CPUID_EXT_ISAR4 "c2, 4"
+#define CPUID_EXT_ISAR5 "c2, 5"
+
#ifdef CONFIG_CPU_CP15
#define read_cpuid(reg) \
({ \
@@ -18,9 +33,21 @@
: "cc"); \
__val; \
})
+#define read_cpuid_ext(ext_reg) \
+ ({ \
+ unsigned int __val; \
+ asm("mrc p15, 0, %0, c0, " ext_reg \
+ : "=r" (__val) \
+ : \
+ : "cc"); \
+ __val; \
+ })
+#elif defined(CONFIG_CPU_V7M)
+#define read_cpuid(reg) (*(unsigned int *)0xe000ed00)
#else
extern unsigned int processor_id;
#define read_cpuid(reg) (processor_id)
+#define read_cpuid_ext(reg) 0
#endif
/*
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 8196abfa2d8e..22d887df8832 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -55,6 +55,9 @@ typedef struct user_fp elf_fpregset_t;
#define R_ARM_MOVW_ABS_NC 43
#define R_ARM_MOVT_ABS 44
+#define R_ARM_THM_JUMP24 30
+#define R_ARM_THM_CALL 10
+
/*
* These are used to set parameters in the core dumps.
*/
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 9ee743b95de8..0efee0f0c08e 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -99,6 +99,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: ldrt %0, [%3]\n"
" teq %0, %1\n"
+ " it eq\n"
"2: streqt %2, [%3]\n"
"3:\n"
" .section __ex_table,\"a\"\n"
diff --git a/arch/arm/include/asm/glue.h b/arch/arm/include/asm/glue.h
index a0e39d5d00c9..0a3bb3d8fab6 100644
--- a/arch/arm/include/asm/glue.h
+++ b/arch/arm/include/asm/glue.h
@@ -115,6 +115,14 @@
# endif
#endif
+#ifdef CONFIG_CPU_ABRT_EV7M
+# ifdef CPU_DABORT_HANDLER
+# define MULTI_DABORT 1
+# else
+# define CPU_DABORT_HANDLER v7m_early_abort
+# endif
+#endif
+
#ifndef CPU_DABORT_HANDLER
#error Unknown data abort handler type
#endif
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 64f2252a25cd..33d19e4160c4 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -24,6 +24,8 @@
#define L2X0_CACHE_TYPE 0x004
#define L2X0_CTRL 0x100
#define L2X0_AUX_CTRL 0x104
+#define L2X0_TAG_LATENCY_CTRL 0x108
+#define L2X0_DATA_LATENCY_CTRL 0x10C
#define L2X0_EVENT_CNT_CTRL 0x200
#define L2X0_EVENT_CNT1_CFG 0x204
#define L2X0_EVENT_CNT0_CFG 0x208
@@ -49,8 +51,34 @@
#define L2X0_LINE_TAG 0xF30
#define L2X0_DEBUG_CTRL 0xF40
+/* Interrupt bits */
+#define L2X0_INTR_ECNTR 0x01
+
+/* Aux Control bits */
+#define L2X0_AUX_CTRL_EMBUS (0x01<<20)
+
+/* Event Counter Control bits */
+#define L2X0_EVENT_CONTROL_ENABLE 0x1
+#define L2X0_EVENT_CONTROL_RESET_ALL 0x6
+
+/* Event Counter Config bits */
+#define L2X0_EVENT_CONFIG_DISABLED 0x0
+#define L2X0_EVENT_CONFIG_CO (0x1<<2)
+#define L2X0_EVENT_CONFIG_DRHIT (0x2<<2)
+#define L2X0_EVENT_CONFIG_DRREQ (0x3<<2)
+#define L2X0_EVENT_CONFIG_DWHIT (0x4<<2)
+#define L2X0_EVENT_CONFIG_DWREQ (0x5<<2)
+#define L2X0_EVENT_CONFIG_DWTREQ (0x6<<2)
+#define L2X0_EVENT_CONFIG_IRHIT (0x7<<2)
+#define L2X0_EVENT_CONFIG_IRREQ (0x8<<2)
+#define L2X0_EVENT_CONFIG_WA (0x9<<2)
+#define L2X0_EVENT_INTERRUPT_ON_INC 0x1
+#define L2X0_EVENT_INTERRUPT_ON_OVF 0x2
+#define L2X0_EVENT_INTERRUPT_DISABLED 0x3
+
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
+extern bool l2x0_disabled;
#endif
#endif
diff --git a/arch/arm/include/asm/hardware/debug-pl01x.S b/arch/arm/include/asm/hardware/debug-pl01x.S
index f9fd083eff63..1605bc1a64bb 100644
--- a/arch/arm/include/asm/hardware/debug-pl01x.S
+++ b/arch/arm/include/asm/hardware/debug-pl01x.S
@@ -12,6 +12,14 @@
*/
#include <linux/amba/serial.h>
+ .macro inituart,rd,rx
+ mov \rd, #0x10
+ str \rd, [\rx, #UART011_IBRD]
+ mov \rd, #0xc300
+ orr \rd, #0x0001
+ str \rd, [\rx, #UART011_CR]
+ .endm
+
.macro senduart,rd,rx
strb \rd, [\rx, #UART01x_DR]
.endm
diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
index 6d09974e6646..5dbb6de221ce 100644
--- a/arch/arm/include/asm/irqflags.h
+++ b/arch/arm/include/asm/irqflags.h
@@ -10,6 +10,15 @@
*/
#if __LINUX_ARM_ARCH__ >= 6
+#ifdef CONFIG_CPU_V7M
+#define raw_local_irq_save(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, primask @ local_irq_save\n" \
+ "cpsid i" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+#else
#define raw_local_irq_save(x) \
({ \
__asm__ __volatile__( \
@@ -17,6 +26,7 @@
"cpsid i" \
: "=r" (x) : : "memory", "cc"); \
})
+#endif
#define raw_local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
#define raw_local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc")
@@ -103,6 +113,35 @@
#endif
+#ifdef CONFIG_CPU_V7M
+
+/*
+ * Save the current interrupt enable state.
+ */
+#define raw_local_save_flags(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, primask @ local_save_flags" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+
+/*
+ * restore saved IRQ & FIQ state
+ */
+#define raw_local_irq_restore(x) \
+ __asm__ __volatile__( \
+ "msr primask, %0 @ local_irq_restore\n" \
+ : \
+ : "r" (x) \
+ : "memory", "cc")
+
+#define raw_irqs_disabled_flags(flags) \
+({ \
+ (int)((flags) & 1); \
+})
+
+#else
+
/*
* Save the current interrupt enable state.
*/
@@ -128,5 +167,7 @@
(int)((flags) & PSR_I_BIT); \
})
+#endif /* CONFIG_CPU_V7M */
+
#endif
#endif
diff --git a/arch/arm/include/asm/locks.h b/arch/arm/include/asm/locks.h
index ef4c897772d1..c6f0c9363f0f 100644
--- a/arch/arm/include/asm/locks.h
+++ b/arch/arm/include/asm/locks.h
@@ -24,6 +24,7 @@
" teq ip, #0\n" \
" bne 1b\n" \
" teq lr, #0\n" \
+" itt mi\n" \
" movmi ip, %0\n" \
" blmi " #fail \
: \
@@ -43,6 +44,7 @@
" teq ip, #0\n" \
" bne 1b\n" \
" teq lr, #0\n" \
+" itet mi\n" \
" movmi ip, %1\n" \
" movpl ip, #0\n" \
" blmi " #fail "\n" \
@@ -65,6 +67,7 @@
" teq ip, #0\n" \
" bne 1b\n" \
" cmp lr, #0\n" \
+" itt le\n" \
" movle ip, %0\n" \
" blle " #wake \
: \
@@ -91,6 +94,7 @@
" teq ip, #0\n" \
" bne 1b\n" \
" teq lr, #0\n" \
+" itt ne\n" \
" movne ip, %0\n" \
" blne " #fail \
: \
@@ -150,6 +154,7 @@
" subs lr, lr, %1\n" \
" str lr, [%0]\n" \
" msr cpsr_c, ip\n" \
+" itt mi\n" \
" movmi ip, %0\n" \
" blmi " #fail \
: \
@@ -170,6 +175,7 @@
" subs lr, lr, %2\n" \
" str lr, [%1]\n" \
" msr cpsr_c, ip\n" \
+" itet mi\n" \
" movmi ip, %1\n" \
" movpl ip, #0\n" \
" blmi " #fail "\n" \
@@ -193,6 +199,7 @@
" adds lr, lr, %1\n" \
" str lr, [%0]\n" \
" msr cpsr_c, ip\n" \
+" itt le\n" \
" movle ip, %0\n" \
" blle " #wake \
: \
@@ -220,6 +227,7 @@
" subs lr, lr, %1\n" \
" str lr, [%0]\n" \
" msr cpsr_c, ip\n" \
+" itt ne\n" \
" movne ip, %0\n" \
" blne " #fail \
: \
@@ -239,6 +247,7 @@
" adds lr, lr, %1\n" \
" str lr, [%0]\n" \
" msr cpsr_c, ip\n" \
+" itt cs\n" \
" movcs ip, %0\n" \
" blcs " #wake \
: \
@@ -262,6 +271,7 @@
" adds lr, lr, %1\n" \
" str lr, [%0]\n" \
" msr cpsr_c, ip\n" \
+" itt eq\n" \
" moveq ip, %0\n" \
" bleq " #wake \
: \
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 0202a7c20e62..4c541922f2f4 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -45,7 +45,12 @@
* and PAGE_OFFSET - it must be within 32MB of the kernel text.
*/
#define MODULES_END (PAGE_OFFSET)
+#ifndef CONFIG_THUMB2_KERNEL
#define MODULES_VADDR (MODULES_END - 16*1048576)
+#else
+/* smaller range for Thumb-2 symbols relocation (2^24)*/
+#define MODULES_VADDR (MODULES_END - 8*1048576)
+#endif
#if TASK_SIZE > MODULES_VADDR
#error Top of user space clashes with start of module space
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index b561584d04a1..68870c776671 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -6,6 +6,7 @@
typedef struct {
#ifdef CONFIG_CPU_HAS_ASID
unsigned int id;
+ spinlock_t id_lock;
#endif
unsigned int kvm_seq;
} mm_context_t;
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index 263fed05ea33..42939ee430a3 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -43,12 +43,23 @@ void __check_kvm_seq(struct mm_struct *mm);
#define ASID_FIRST_VERSION (1 << ASID_BITS)
extern unsigned int cpu_last_asid;
+#ifdef CONFIG_SMP
+DECLARE_PER_CPU(struct mm_struct *, current_mm);
+#endif
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void __new_context(struct mm_struct *mm);
static inline void check_context(struct mm_struct *mm)
{
+ /*
+ * This code is executed with interrupts enabled. Therefore,
+ * mm->context.id cannot be updated to the latest ASID version
+ * on a different CPU (and condition below not triggered)
+ * without first getting an IPI to reset the context. The
+ * alternative is to take a read_lock on mm->context.id_lock
+ * (after changing its type to rwlock_t).
+ */
if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS))
__new_context(mm);
@@ -62,8 +73,10 @@ static inline void check_context(struct mm_struct *mm)
static inline void check_context(struct mm_struct *mm)
{
+#ifdef CONFIG_MMU
if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
__check_kvm_seq(mm);
+#endif
}
#define init_new_context(tsk,mm) 0
@@ -105,6 +118,10 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
__flush_icache_all();
#endif
if (!cpu_test_and_set(cpu, next->cpu_vm_mask) || prev != next) {
+#ifdef CONFIG_SMP
+ struct mm_struct **crt_mm = &per_cpu(current_mm, cpu);
+ *crt_mm = next;
+#endif
check_context(next);
cpu_switch_mm(next->pgd, next);
if (cache_is_vivt())
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 24b168dc31a3..e4dfa69abb68 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -1,15 +1,27 @@
#ifndef _ASM_ARM_MODULE_H
#define _ASM_ARM_MODULE_H
-struct mod_arch_specific
-{
- int foo;
-};
-
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+struct unwind_table;
+
+struct mod_arch_specific
+{
+#ifdef CONFIG_ARM_UNWIND
+ Elf_Shdr *unw_sec_init;
+ Elf_Shdr *unw_sec_devinit;
+ Elf_Shdr *unw_sec_core;
+ Elf_Shdr *sec_init_text;
+ Elf_Shdr *sec_devinit_text;
+ Elf_Shdr *sec_core_text;
+ struct unwind_table *unwind_init;
+ struct unwind_table *unwind_devinit;
+ struct unwind_table *unwind_core;
+#endif
+};
+
/*
* Include the ARM architecture version.
*/
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
index 93226cf23ae0..5c3ede822a6e 100644
--- a/arch/arm/include/asm/mutex.h
+++ b/arch/arm/include/asm/mutex.h
@@ -111,8 +111,11 @@ __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
"1: ldrex %0, [%3] \n\t"
"subs %1, %0, #1 \n\t"
+ "it eq\n\t"
"strexeq %2, %1, [%3] \n\t"
+ "it lt\n\t"
"movlt %0, #0 \n\t"
+ "it eq\n\t"
"cmpeq %2, #0 \n\t"
"bgt 1b "
diff --git a/arch/arm/include/asm/page-nommu.h b/arch/arm/include/asm/page-nommu.h
index 3574c0deb37f..d1b162a18dcb 100644
--- a/arch/arm/include/asm/page-nommu.h
+++ b/arch/arm/include/asm/page-nommu.h
@@ -43,7 +43,4 @@ typedef unsigned long pgprot_t;
#define __pmd(x) (x)
#define __pgprot(x) (x)
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
#endif
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index db80203b68e0..d9faa2b32dfb 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -209,6 +209,14 @@
# define CPU_NAME cpu_v7
# endif
# endif
+# ifdef CONFIG_CPU_V7M
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_v7m
+# endif
+# endif
#endif
#ifndef __ASSEMBLY__
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 1845892260e7..c6dcc6a31a50 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -57,7 +57,15 @@ struct thread_struct {
#ifdef CONFIG_MMU
#define nommu_start_thread(regs) do { } while (0)
#else
+#ifndef CONFIG_CPU_V7M
#define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
+#else
+#define nommu_start_thread(regs) do { \
+ regs->ARM_r10 = current->mm->start_data; \
+ regs->ARM_sp -= 32; /* exception return state */ \
+ regs->ARM_EXC_lr = 0xfffffffdL; /* exception lr */ \
+} while (0)
+#endif
#endif
#define start_thread(regs,pc,sp) \
@@ -71,7 +79,8 @@ struct thread_struct {
regs->ARM_cpsr = USR26_MODE; \
if (elf_hwcap & HWCAP_THUMB && pc & 1) \
regs->ARM_cpsr |= PSR_T_BIT; \
- regs->ARM_pc = pc & ~1; /* pc */ \
+ regs->ARM_cpsr |= PSR_ENDSTATE; \
+ regs->ARM_pc = pc /*& ~1*/; /* pc */ \
regs->ARM_sp = sp; /* sp */ \
regs->ARM_r2 = stack[2]; /* r2 (envp) */ \
regs->ARM_r1 = stack[1]; /* r1 (argv) */ \
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 236a06b9b7ce..1f7419c9fcc0 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -37,19 +37,29 @@
#define FIQ26_MODE 0x00000001
#define IRQ26_MODE 0x00000002
#define SVC26_MODE 0x00000003
+#ifndef CONFIG_CPU_V7M
#define USR_MODE 0x00000010
+#define SVC_MODE 0x00000013
+#else
+#define USR_MODE 0x00000000
+#define SVC_MODE 0x00000000
+#endif
#define FIQ_MODE 0x00000011
#define IRQ_MODE 0x00000012
-#define SVC_MODE 0x00000013
#define ABT_MODE 0x00000017
#define UND_MODE 0x0000001b
#define SYSTEM_MODE 0x0000001f
#define MODE32_BIT 0x00000010
#define MODE_MASK 0x0000001f
+#ifndef CONFIG_CPU_V7M
#define PSR_T_BIT 0x00000020
+#else
+#define PSR_T_BIT 0x01000000
+#endif
#define PSR_F_BIT 0x00000040
#define PSR_I_BIT 0x00000080
#define PSR_A_BIT 0x00000100
+#define PSR_E_BIT 0x00000200
#define PSR_J_BIT 0x01000000
#define PSR_Q_BIT 0x08000000
#define PSR_V_BIT 0x10000000
@@ -65,6 +75,30 @@
#define PSR_x 0x0000ff00 /* Extension */
#define PSR_c 0x000000ff /* Control */
+/*
+ * ARMv7 groups of APSR bits
+ */
+#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */
+#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
+#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */
+
+/*
+ * Default endianness state
+ */
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define PSR_ENDSTATE PSR_E_BIT
+#else
+#define PSR_ENDSTATE 0
+#endif
+
+/*
+ * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
+ * process is located in memory.
+ */
+#define PT_TEXT_ADDR 0x10000
+#define PT_DATA_ADDR 0x10004
+#define PT_TEXT_END_ADDR 0x10008
+
#ifndef __ASSEMBLY__
/*
@@ -76,6 +110,28 @@ struct pt_regs {
long uregs[18];
};
+#ifdef CONFIG_CPU_V7M
+/* Automatically saved registers */
+#define ARM_cpsr uregs[17]
+#define ARM_pc uregs[16]
+#define ARM_lr uregs[15]
+#define ARM_ip uregs[14]
+#define ARM_r3 uregs[13]
+#define ARM_r2 uregs[12]
+#define ARM_r1 uregs[11]
+#define ARM_r0 uregs[10]
+/* saved by the exception entry code */
+#define ARM_EXC_lr uregs[9]
+#define ARM_sp uregs[8]
+#define ARM_fp uregs[7]
+#define ARM_r10 uregs[6]
+#define ARM_r9 uregs[5]
+#define ARM_r8 uregs[4]
+#define ARM_r7 uregs[3]
+#define ARM_r6 uregs[2]
+#define ARM_r5 uregs[1]
+#define ARM_r4 uregs[0]
+#else
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
@@ -94,6 +150,7 @@ struct pt_regs {
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
+#endif
#ifdef __KERNEL__
@@ -125,6 +182,7 @@ struct pt_regs {
*/
static inline int valid_user_regs(struct pt_regs *regs)
{
+#ifndef CONFIG_CPU_V7M
if (user_mode(regs) && (regs->ARM_cpsr & PSR_I_BIT) == 0) {
regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT);
return 1;
@@ -138,6 +196,9 @@ static inline int valid_user_regs(struct pt_regs *regs)
regs->ARM_cpsr |= USR_MODE;
return 0;
+#else
+ return 1;
+#endif
}
#define instruction_pointer(regs) (regs)->ARM_pc
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 2b41ebbfa7ff..cfc6f6dc98c4 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -23,15 +23,38 @@
#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+#ifdef CONFIG_ARM_ERRATA_351422
+#define spinlock_backoff_delay() \
+{ \
+ unsigned int delay; \
+ __asm__ __volatile__( \
+ "1: mrc p15, 0, %0, c0, c0, 5\n" \
+ " and %0, %0, #0xf\n" \
+ " mov %0, %0, lsl #8\n" \
+ "2: subs %0, %0, #1\n" \
+ " bpl 2b\n" \
+ : "=&r" (delay) \
+ : \
+ : "cc" ); \
+}
+#else
+#define spinlock_backoff_delay() \
+ __asm__ __volatile__("1: \n");
+#endif
+
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
unsigned long tmp;
+ spinlock_backoff_delay();
__asm__ __volatile__(
-"1: ldrex %0, [%1]\n"
+" ldrex %0, [%1]\n"
" teq %0, #0\n"
#ifdef CONFIG_CPU_32v6K
+" itee ne\n"
" wfene\n"
+#else
+" itt eq\n"
#endif
" strexeq %0, %2, [%1]\n"
" teqeq %0, #0\n"
@@ -47,9 +70,11 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
{
unsigned long tmp;
+ spinlock_backoff_delay();
__asm__ __volatile__(
" ldrex %0, [%1]\n"
" teq %0, #0\n"
+" it eq\n"
" strexeq %0, %2, [%1]"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
@@ -90,11 +115,15 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
{
unsigned long tmp;
+ spinlock_backoff_delay();
__asm__ __volatile__(
-"1: ldrex %0, [%1]\n"
+" ldrex %0, [%1]\n"
" teq %0, #0\n"
#ifdef CONFIG_CPU_32v6K
+" ite ne\n"
" wfene\n"
+#else
+" it eq\n"
#endif
" strexeq %0, %2, [%1]\n"
" teq %0, #0\n"
@@ -110,9 +139,11 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
{
unsigned long tmp;
+ spinlock_backoff_delay();
__asm__ __volatile__(
"1: ldrex %0, [%1]\n"
" teq %0, #0\n"
+" it eq\n"
" strexeq %0, %2, [%1]"
: "=&r" (tmp)
: "r" (&rw->lock), "r" (0x80000000)
@@ -160,9 +191,15 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
{
unsigned long tmp, tmp2;
+ spinlock_backoff_delay();
__asm__ __volatile__(
-"1: ldrex %0, [%2]\n"
+" ldrex %0, [%2]\n"
" adds %0, %0, #1\n"
+#ifdef CONFIG_CPU_32v6K
+" itet pl\n"
+#else
+" itt pl\n"
+#endif
" strexpl %1, %0, [%2]\n"
#ifdef CONFIG_CPU_32v6K
" wfemi\n"
@@ -182,14 +219,16 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
smp_mb();
+ spinlock_backoff_delay();
__asm__ __volatile__(
-"1: ldrex %0, [%2]\n"
+" ldrex %0, [%2]\n"
" sub %0, %0, #1\n"
" strex %1, %0, [%2]\n"
" teq %1, #0\n"
" bne 1b"
#ifdef CONFIG_CPU_32v6K
"\n cmp %0, #0\n"
+" itt eq\n"
" mcreq p15, 0, %0, c7, c10, 4\n"
" seveq"
#endif
@@ -205,6 +244,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
__asm__ __volatile__(
"1: ldrex %0, [%2]\n"
" adds %0, %0, #1\n"
+" it pl\n"
" strexpl %1, %0, [%2]\n"
: "=&r" (tmp), "+r" (tmp2)
: "r" (&rw->lock)
diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h
new file mode 100644
index 000000000000..4d0a16441b29
--- /dev/null
+++ b/arch/arm/include/asm/stacktrace.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_STACKTRACE_H
+#define __ASM_STACKTRACE_H
+
+struct stackframe {
+ unsigned long fp;
+ unsigned long sp;
+ unsigned long lr;
+ unsigned long pc;
+};
+
+extern int unwind_frame(struct stackframe *frame);
+extern void walk_stackframe(struct stackframe *frame,
+ int (*fn)(struct stackframe *, void *), void *data);
+
+#endif /* __ASM_STACKTRACE_H */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 811be55f338e..9eeda3c177de 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -13,6 +13,7 @@
#define CPU_ARCH_ARMv5TEJ 7
#define CPU_ARCH_ARMv6 8
#define CPU_ARCH_ARMv7 9
+#define CPU_ARCH_ARMv7M 10
/*
* CR1 bits (CP#15 CR1)
@@ -198,7 +199,9 @@ static inline void set_copro_access(unsigned int val)
* so enable interrupts over the context switch to avoid high
* latency.
*/
+#ifndef CONFIG_CPU_V7M
#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+#endif
/*
* switch_to(prev, next) should switch from task `prev' to `next'
@@ -321,6 +324,56 @@ extern void enable_hlt(void);
#ifndef CONFIG_SMP
#include <asm-generic/cmpxchg.h>
+#elif __LINUX_ARM_ARCH__ >= 6
+extern void __bad_cmpxchg(volatile void *ptr, int size);
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long oldval, res;
+
+ switch (size) {
+ case 1:
+ do {
+ asm volatile("@ __cmpxchg1\n"
+ " ldrexb %1, [%2]\n"
+ " mov %0, #0\n"
+ " teq %1, %3\n"
+ " it eq\n"
+ " strexeqb %0, %4, [%2]\n"
+ : "=&r" (res), "=&r" (oldval)
+ : "r" (ptr), "Ir" (old), "r" (new)
+ : "cc");
+ } while (res);
+ break;
+
+ case 4:
+ do {
+ asm volatile("@ __cmpxchg4\n"
+ " ldrex %1, [%2]\n"
+ " mov %0, #0\n"
+ " teq %1, %3\n"
+ " it eq\n"
+ " strexeq %0, %4, [%2]\n"
+ : "=&r" (res), "=&r" (oldval)
+ : "r" (ptr), "Ir" (old), "r" (new)
+ : "cc");
+ } while (res);
+ break;
+
+ default:
+ __bad_cmpxchg(ptr, size);
+ oldval = 0;
+ }
+
+ return oldval;
+}
+
+#define cmpxchg(ptr,o,n) \
+ ((__typeof__(*(ptr)))__cmpxchg((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))))
#endif
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index b9dc8a842573..4f8848260ee2 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -99,6 +99,8 @@ static inline struct thread_info *current_thread_info(void)
#define thread_saved_pc(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
+#define thread_saved_sp(tsk) \
+ ((unsigned long)(task_thread_info(tsk)->cpu_context.sp))
#define thread_saved_fp(tsk) \
((unsigned long)(task_thread_info(tsk)->cpu_context.fp))
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index b543a054a17e..214c6501b3af 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -39,6 +39,11 @@
#define TLB_V6_D_ASID (1 << 17)
#define TLB_V6_I_ASID (1 << 18)
+/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
+#define TLB_V7_UIS_PAGE (1 << 19)
+#define TLB_V7_UIS_FULL (1 << 20)
+#define TLB_V7_UIS_ASID (1 << 21)
+
#define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */
#define TLB_DCLEAN (1 << 30)
#define TLB_WB (1 << 31)
@@ -158,9 +163,17 @@
# define v6wbi_always_flags (-1UL)
#endif
+#ifdef CONFIG_SMP
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
+ TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
+#else
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
+ TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
+#endif
+
#ifdef CONFIG_CPU_TLB_V7
-# define v7wbi_possible_flags v6wbi_tlb_flags
-# define v7wbi_always_flags v6wbi_tlb_flags
+# define v7wbi_possible_flags v7wbi_tlb_flags
+# define v7wbi_always_flags v7wbi_tlb_flags
# ifdef _TLB
# define MULTI_TLB 1
# else
@@ -178,6 +191,7 @@
#ifndef __ASSEMBLY__
#include <linux/sched.h>
+#include <asm/cputype.h>
struct cpu_tlb_fns {
void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
@@ -296,10 +310,11 @@ static inline void local_flush_tlb_all(void)
asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V7_UIS_FULL))
+ asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
- if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
- TLB_V6_I_PAGE | TLB_V6_D_PAGE |
- TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL | TLB_V6_U_FULL |
+ TLB_V7_UIS_FULL)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
@@ -333,10 +348,11 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_I_ASID))
asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
+ if (tlb_flag(TLB_V7_UIS_ASID))
+ asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
- if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
- TLB_V6_I_PAGE | TLB_V6_D_PAGE |
- TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ if (tlb_flag(TLB_V6_I_ASID | TLB_V6_D_ASID | TLB_V6_U_ASID |
+ TLB_V7_UIS_ASID)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
@@ -373,10 +389,11 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+ if (tlb_flag(TLB_V7_UIS_PAGE))
+ asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
- if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
- TLB_V6_I_PAGE | TLB_V6_D_PAGE |
- TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ if (tlb_flag(TLB_V6_I_PAGE | TLB_V6_D_PAGE | TLB_V6_U_PAGE |
+ TLB_V7_UIS_PAGE)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
@@ -410,10 +427,11 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
+ if (tlb_flag(TLB_V7_UIS_PAGE))
+ asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
- if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
- TLB_V6_I_PAGE | TLB_V6_D_PAGE |
- TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ if (tlb_flag(TLB_V6_I_PAGE | TLB_V6_D_PAGE | TLB_V6_U_PAGE |
+ TLB_V7_UIS_PAGE)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
@@ -474,21 +492,70 @@ static inline void clean_pmd_entry(pmd_t *pmd)
#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
#ifndef CONFIG_SMP
-#define flush_tlb_all local_flush_tlb_all
-#define flush_tlb_mm local_flush_tlb_mm
-#define flush_tlb_page local_flush_tlb_page
-#define flush_tlb_kernel_page local_flush_tlb_kernel_page
-#define flush_tlb_range local_flush_tlb_range
-#define flush_tlb_kernel_range local_flush_tlb_kernel_range
+#define tlb_ops_need_broadcast() 0
#else
-extern void flush_tlb_all(void);
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
-extern void flush_tlb_kernel_page(unsigned long kaddr);
-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+/* all SMP configurations have the extended CPUID registers */
+static inline int tlb_ops_need_broadcast(void)
+{
+ return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
+}
#endif
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
+extern void smp_flush_tlb_kernel_page(unsigned long kaddr);
+extern void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+static inline void flush_tlb_all(void)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_all();
+ else
+ local_flush_tlb_all();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_mm(mm);
+ else
+ local_flush_tlb_mm(mm);
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_page(vma, uaddr);
+ else
+ local_flush_tlb_page(vma, uaddr);
+}
+
+static inline void flush_tlb_kernel_page(unsigned long kaddr)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_kernel_page(kaddr);
+ else
+ local_flush_tlb_kernel_page(kaddr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_range(vma, start, end);
+ else
+ local_flush_tlb_range(vma, start, end);
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ if (tlb_ops_need_broadcast())
+ smp_flush_tlb_kernel_range(start, end);
+ else
+ local_flush_tlb_kernel_range(start, end);
+}
+
/*
* if PG_dcache_dirty is set for the page, we need to ensure that any
* cache entries for the kernels virtual memory range are written
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index aa399aec568e..491960bf4260 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -25,5 +25,6 @@ static inline int in_exception_text(unsigned long ptr)
}
extern void __init early_trap_init(void);
+extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
#endif
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 7897464e0c24..7f92975565da 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -13,6 +13,8 @@
*/
#include <linux/string.h>
#include <linux/thread_info.h>
+#include <linux/sched.h>
+#include <asm/unified.h>
#include <asm/errno.h>
#include <asm/memory.h>
#include <asm/domain.h>
@@ -69,7 +71,7 @@ static inline void set_fs(mm_segment_t fs)
#define __addr_ok(addr) ({ \
unsigned long flag; \
- __asm__("cmp %2, %0; movlo %0, #0" \
+ __asm__("cmp %2, %0; it lo; movlo %0, #0" \
: "=&r" (flag) \
: "0" (current_thread_info()->addr_limit), "r" (addr) \
: "cc"); \
@@ -79,7 +81,7 @@ static inline void set_fs(mm_segment_t fs)
#define __range_ok(addr,size) ({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
- __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \
+ __asm__("adds %1, %2, %3; it cc; sbcccs %1, %1, %0; it cc; movcc %0, #0" \
: "=&r" (flag), "=&r" (roksum) \
: "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \
: "cc"); \
@@ -365,8 +367,10 @@ do { \
#define __put_user_asm_dword(x,__pu_addr,err) \
__asm__ __volatile__( \
- "1: strt " __reg_oper1 ", [%1], #4\n" \
- "2: strt " __reg_oper0 ", [%1]\n" \
+ ARM( "1: strt " __reg_oper1 ", [%1], #4\n" ) \
+ ARM( "2: strt " __reg_oper0 ", [%1]\n" ) \
+ THUMB( "1: strt " __reg_oper1 ", [%1]\n" ) \
+ THUMB( "2: strt " __reg_oper0 ", [%1, #4]\n" ) \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h
new file mode 100644
index 000000000000..82194c0ca1ec
--- /dev/null
+++ b/arch/arm/include/asm/unified.h
@@ -0,0 +1,126 @@
+/*
+ * include/asm-arm/unified.h - Unified Assembler Syntax helper macros
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_UNIFIED_H
+#define __ASM_UNIFIED_H
+
+#if defined(__ASSEMBLY__) && defined(CONFIG_ARM_ASM_UNIFIED)
+ .syntax unified
+#endif
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+#if __GNUC__ < 4
+#error Thumb-2 kernel requires gcc >= 4
+#endif
+
+/* The CPSR bit describing the instruction set (Thumb) */
+#define PSR_ISETSTATE PSR_T_BIT
+
+#define ARM(x...)
+#define THUMB(x...) x
+#define W(instr) instr.w
+#define BSYM(sym) sym + 1
+
+#else /* !CONFIG_THUMB2_KERNEL */
+
+/* The CPSR bit describing the instruction set (ARM) */
+#define PSR_ISETSTATE 0
+
+#define ARM(x...) x
+#define THUMB(x...)
+#define W(instr) instr
+#define BSYM(sym) sym
+
+#endif /* CONFIG_THUMB2_KERNEL */
+
+#ifndef CONFIG_ARM_ASM_UNIFIED
+
+/*
+ * If the unified assembly syntax isn't used (in ARM mode), these
+ * macros expand to an empty string
+ */
+#ifdef __ASSEMBLY__
+ .macro it, cond
+ .endm
+ .macro itt, cond
+ .endm
+ .macro ite, cond
+ .endm
+ .macro ittt, cond
+ .endm
+ .macro itte, cond
+ .endm
+ .macro itet, cond
+ .endm
+ .macro itee, cond
+ .endm
+ .macro itttt, cond
+ .endm
+ .macro ittte, cond
+ .endm
+ .macro ittet, cond
+ .endm
+ .macro ittee, cond
+ .endm
+ .macro itett, cond
+ .endm
+ .macro itete, cond
+ .endm
+ .macro iteet, cond
+ .endm
+ .macro iteee, cond
+ .endm
+#else /* !__ASSEMBLY__ */
+__asm__(
+" .macro it, cond\n"
+" .endm\n"
+" .macro itt, cond\n"
+" .endm\n"
+" .macro ite, cond\n"
+" .endm\n"
+" .macro ittt, cond\n"
+" .endm\n"
+" .macro itte, cond\n"
+" .endm\n"
+" .macro itet, cond\n"
+" .endm\n"
+" .macro itee, cond\n"
+" .endm\n"
+" .macro itttt, cond\n"
+" .endm\n"
+" .macro ittte, cond\n"
+" .endm\n"
+" .macro ittet, cond\n"
+" .endm\n"
+" .macro ittee, cond\n"
+" .endm\n"
+" .macro itett, cond\n"
+" .endm\n"
+" .macro itete, cond\n"
+" .endm\n"
+" .macro iteet, cond\n"
+" .endm\n"
+" .macro iteee, cond\n"
+" .endm\n");
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARM_ASM_UNIFIED */
+
+#endif /* !CONFIG_ARM_ASM_UNIFIED */
diff --git a/arch/arm/include/asm/unwind.h b/arch/arm/include/asm/unwind.h
new file mode 100644
index 000000000000..a5edf421005c
--- /dev/null
+++ b/arch/arm/include/asm/unwind.h
@@ -0,0 +1,69 @@
+/*
+ * arch/arm/include/asm/unwind.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_UNWIND_H
+#define __ASM_UNWIND_H
+
+#ifndef __ASSEMBLY__
+
+/* Unwind reason code according the the ARM EABI documents */
+enum unwind_reason_code {
+ URC_OK = 0, /* operation completed successfully */
+ URC_CONTINUE_UNWIND = 8,
+ URC_FAILURE = 9 /* unspecified failure of some kind */
+};
+
+struct unwind_idx {
+ unsigned long addr;
+ unsigned long insn;
+};
+
+struct unwind_table {
+ struct list_head list;
+ struct unwind_idx *start;
+ struct unwind_idx *stop;
+ unsigned long begin_addr;
+ unsigned long end_addr;
+};
+
+extern struct unwind_table *unwind_table_add(unsigned long start,
+ unsigned long size,
+ unsigned long text_addr,
+ unsigned long text_size);
+extern void unwind_table_del(struct unwind_table *tab);
+extern void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk);
+
+#ifdef CONFIG_ARM_UNWIND
+extern int __init unwind_init(void);
+#else
+static inline int __init unwind_init(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_ARM_UNWIND
+#define UNWIND(code...) code
+#else
+#define UNWIND(code...)
+#endif
+
+#endif /* __ASM_UNWIND_H */
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h
index 422f3cc204a2..79ccd6cedb59 100644
--- a/arch/arm/include/asm/vfpmacros.h
+++ b/arch/arm/include/asm/vfpmacros.h
@@ -25,6 +25,7 @@
VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
cmp \tmp, #2 @ 32 x 64bit registers?
+ ite eq
ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31}
addne \base, \base, #32*4 @ step over unused register space
#endif
@@ -32,6 +33,9 @@
@ write all the working registers out of the VFP
.macro VFPFSTMIA, base, tmp
+#ifdef CONFIG_ARM_ERRATUM_451034
+ dmb
+#endif
#if __LINUX_ARM_ARCH__ < 6
STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15}
#else
@@ -41,6 +45,7 @@
VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
cmp \tmp, #2 @ 32 x 64bit registers?
+ ite eq
stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31}
addne \base, \base, #32*4 @ step over unused register space
#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 4305345987d3..3f30f220f32c 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,10 +10,16 @@ endif
# Object file lists.
-obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \
+obj-y := compat.o elf.o entry-common.o irq.o \
process.o ptrace.o setup.o signal.o \
sys_arm.o stacktrace.o time.o traps.o
+ifeq ($(CONFIG_CPU_V7M),y)
+obj-y += entry-v7m.o
+else
+obj-y += entry-armv.o
+endif
+
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o
obj-$(CONFIG_FIQ) += fiq.o
@@ -29,6 +35,7 @@ obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_ARM_UNWIND) += unwind.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
@@ -44,5 +51,6 @@ endif
head-y := head$(MMUEXT).o
obj-$(CONFIG_DEBUG_LL) += debug.o
+obj-$(CONFIG_DEBUG_LL_CONSOLE) += early_printk.o
extra-y := $(head-y) init_task.o vmlinux.lds
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 531e1860e546..6b5a79d64807 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -47,8 +47,10 @@ extern void __aeabi_uidiv(void);
extern void __aeabi_uidivmod(void);
extern void __aeabi_ulcmp(void);
+#ifndef CONFIG_CPU_V7M
extern void fpundefinstr(void);
extern void fp_enter(void);
+#endif
/*
* This has a special calling convention; it doesn't
@@ -66,7 +68,9 @@ extern void fp_enter(void);
* floating point math emulator support.
* These symbols will never change their calling convention...
*/
+#ifndef CONFIG_CPU_V7M
EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
+#endif
EXPORT_SYMBOL_ALIAS(fp_printk,printk);
EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 4a881258bb17..009c1a126c05 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -79,7 +79,11 @@ int main(void)
DEFINE(S_LR, offsetof(struct pt_regs, ARM_lr));
DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc));
DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr));
+#ifdef CONFIG_CPU_V7M
+ DEFINE(S_EXC_LR, offsetof(struct pt_regs, ARM_EXC_lr));
+#else
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
+#endif
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
BLANK();
#ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index f53c58290543..e95a5b6657f8 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -105,6 +105,7 @@ printhex: adr r2, hexbuf
1: and r1, r0, #15
mov r0, r0, lsr #4
cmp r1, #10
+ ite lt
addlt r1, r1, #'0'
addge r1, r1, #'a' - 10
strb r1, [r3, #-1]!
@@ -123,9 +124,11 @@ ENTRY(printascii)
senduart r1, r3
busyuart r2, r3
teq r1, #'\n'
+ itt eq
moveq r1, #'\r'
beq 1b
2: teq r0, #0
+ itt ne
ldrneb r1, [r0], #1
teqne r1, #0
bne 1b
diff --git a/arch/arm/kernel/early_printk.c b/arch/arm/kernel/early_printk.c
new file mode 100644
index 000000000000..a0aea0a5e252
--- /dev/null
+++ b/arch/arm/kernel/early_printk.c
@@ -0,0 +1,38 @@
+/*
+ * linux/arch/arm/kernel/early_printk.c
+ *
+ * Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+
+extern void printch(int);
+
+static void early_serial_write(struct console *con, const char *s, unsigned n)
+{
+ while (*s && n-- > 0) {
+ if (*s == '\n')
+ printch('\r');
+ printch(*s);
+ s++;
+ }
+}
+
+static struct console early_serial_console = {
+ .name = "earlyser",
+ .write = early_serial_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+ register_console(&early_serial_console);
+ return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c
index d4a0da1e48f4..950391f194c4 100644
--- a/arch/arm/kernel/elf.c
+++ b/arch/arm/kernel/elf.c
@@ -78,6 +78,15 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
return 1;
if (cpu_architecture() < CPU_ARCH_ARMv6)
return 1;
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
+ /*
+ * If we have support for OABI programs, we can never allow NX
+ * support - our signal syscall restart mechanism relies upon
+ * being able to execute code placed on the user stack.
+ */
+ return 1;
+#else
return 0;
+#endif
}
EXPORT_SYMBOL(arm_elf_read_implies_exec);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 85040cfeb5e5..fc08364c408c 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -20,6 +20,7 @@
#include <asm/vfpmacros.h>
#include <mach/entry-macro.S>
#include <asm/thread_notify.h>
+#include <asm/unwind.h>
#include "entry-header.S"
@@ -29,12 +30,19 @@
.macro irq_handler
get_irqnr_preamble r5, lr
1: get_irqnr_and_base r0, r6, r5, lr
+ ittt ne
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
- adrne lr, 1b
+#if defined(CONFIG_MACH_REALVIEW_EB) && \
+ defined(CONFIG_CPU_V6) && !defined(CONFIG_SMP)
+ @ GIC bug on RealView EB not allowing register polling
+ blne asm_do_IRQ
+#else
+ adrne lr, BSYM(1b)
bne asm_do_IRQ
+#endif
#ifdef CONFIG_SMP
/*
@@ -44,14 +52,16 @@
* preserved from get_irqnr_and_base above
*/
test_for_ipi r0, r6, r5, lr
+ ittt ne
movne r0, sp
- adrne lr, 1b
+ adrne lr, BSYM(1b)
bne do_IPI
#ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr
+ ittt ne
movne r0, sp
- adrne lr, 1b
+ adrne lr, BSYM(1b)
bne do_local_timer
#endif
#endif
@@ -69,7 +79,10 @@
*/
.macro inv_entry, reason
sub sp, sp, #S_FRAME_SIZE
- stmib sp, {r1 - lr}
+ ARM( stmib sp, {r1 - lr} )
+ THUMB( stmia sp, {r0 - r12} )
+ THUMB( str sp, [sp, #S_SP] )
+ THUMB( str lr, [sp, #S_LR] )
mov r1, #\reason
.endm
@@ -123,17 +136,28 @@ ENDPROC(__und_invalid)
#endif
.macro svc_entry, stack_hole=0
- sub sp, sp, #(S_FRAME_SIZE + \stack_hole)
+ UNWIND(.fnstart )
+ UNWIND(.save {r0 - pc} )
+ sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX( str r0, [sp] ) @ temporarily saved
+ SPFIX( mov r0, sp )
+ SPFIX( tst r0, #4 ) @ test original stack alignment
+ SPFIX( ldr r0, [sp] ) @ restored
+#else
SPFIX( tst sp, #4 )
- SPFIX( bicne sp, sp, #4 )
- stmib sp, {r1 - r12}
+#endif
+ SPFIX( it eq )
+ SPFIX( subeq sp, sp, #4 )
+ stmia sp, {r1 - r12}
ldmia r0, {r1 - r3}
- add r5, sp, #S_SP @ here for interlock avoidance
+ add r5, sp, #S_SP - 4 @ here for interlock avoidance
mov r4, #-1 @ "" "" "" ""
- add r0, sp, #(S_FRAME_SIZE + \stack_hole)
- SPFIX( addne r0, r0, #4 )
- str r1, [sp] @ save the "real" r0 copied
+ add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX( it eq )
+ SPFIX( addeq r0, r0, #4 )
+ str r1, [sp, #-4]! @ save the "real" r0 copied
@ from the exception stack
mov r1, lr
@@ -159,6 +183,7 @@ __dabt_svc:
@
mrs r9, cpsr
tst r3, #PSR_I_BIT
+ it eq
biceq r9, r9, #PSR_I_BIT
@
@@ -193,9 +218,9 @@ __dabt_svc:
@
@ restore SPSR and restart the instruction
@
- ldr r0, [sp, #S_PSR]
- msr spsr_cxsf, r0
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ ldr r2, [sp, #S_PSR]
+ svc_exit r2 @ return from exception
+ UNWIND(.fnend )
ENDPROC(__dabt_svc)
.align 5
@@ -217,17 +242,19 @@ __irq_svc:
str r8, [tsk, #TI_PREEMPT] @ restore preempt count
ldr r0, [tsk, #TI_FLAGS] @ get flags
teq r8, #0 @ if preempt count != 0
+ it ne
movne r0, #0 @ force flags to 0
tst r0, #_TIF_NEED_RESCHED
+ it ne
blne svc_preempt
#endif
- ldr r0, [sp, #S_PSR] @ irqs are already disabled
- msr spsr_cxsf, r0
+ ldr r4, [sp, #S_PSR] @ irqs are already disabled
#ifdef CONFIG_TRACE_IRQFLAGS
- tst r0, #PSR_I_BIT
+ tst r4, #PSR_I_BIT
bleq trace_hardirqs_on
#endif
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ svc_exit r4 @ return from exception
+ UNWIND(.fnend )
ENDPROC(__irq_svc)
.ltorg
@@ -238,6 +265,7 @@ svc_preempt:
1: bl preempt_schedule_irq @ irq en/disable is done inside
ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
tst r0, #_TIF_NEED_RESCHED
+ it eq
moveq pc, r8 @ go again
b 1b
#endif
@@ -260,8 +288,17 @@ __und_svc:
@
@ r0 - instruction
@
+#ifndef CONFIG_THUMB2_KERNEL
ldr r0, [r2, #-4]
- adr r9, 1f
+#else
+ ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2
+ and r9, r0, #0xf800
+ cmp r9, #0xe800 @ 32-bit instruction if xx >= 0
+ itt hs
+ ldrhhs r9, [r2] @ bottom 16 bits
+ orrhs r0, r9, r0, lsl #16
+#endif
+ adr r9, BSYM(1f)
bl call_fpe
mov r0, sp @ struct pt_regs *regs
@@ -275,9 +312,9 @@ __und_svc:
@
@ restore SPSR and restart the instruction
@
- ldr lr, [sp, #S_PSR] @ Get SVC cpsr
- msr spsr_cxsf, lr
- ldmia sp, {r0 - pc}^ @ Restore SVC registers
+ ldr r2, [sp, #S_PSR] @ Get SVC cpsr
+ svc_exit r2 @ return from exception
+ UNWIND(.fnend )
ENDPROC(__und_svc)
.align 5
@@ -289,6 +326,7 @@ __pabt_svc:
@
mrs r9, cpsr
tst r3, #PSR_I_BIT
+ it eq
biceq r9, r9, #PSR_I_BIT
@
@@ -317,9 +355,9 @@ __pabt_svc:
@
@ restore SPSR and restart the instruction
@
- ldr r0, [sp, #S_PSR]
- msr spsr_cxsf, r0
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ ldr r2, [sp, #S_PSR]
+ svc_exit r2 @ return from exception
+ UNWIND(.fnend )
ENDPROC(__pabt_svc)
.align 5
@@ -343,8 +381,11 @@ ENDPROC(__pabt_svc)
#endif
.macro usr_entry
+ UNWIND(.fnstart )
+ UNWIND(.cantunwind ) @ don't unwind the user space
sub sp, sp, #S_FRAME_SIZE
- stmib sp, {r1 - r12}
+ ARM( stmib sp, {r1 - r12} )
+ THUMB( stmia sp, {r0 - r12} )
ldmia r0, {r1 - r3}
add r0, sp, #S_PC @ here for interlock avoidance
@@ -363,7 +404,8 @@ ENDPROC(__pabt_svc)
@ Also, separately save sp_usr and lr_usr
@
stmia r0, {r2 - r4}
- stmdb r0, {sp, lr}^
+ ARM( stmdb r0, {sp, lr}^ )
+ THUMB( store_user_sp_lr r0, r1, S_SP - S_PC )
@
@ Enable the alignment trap while in kernel mode
@@ -418,8 +460,9 @@ __dabt_usr:
@
enable_irq
mov r2, sp
- adr lr, ret_from_exception
+ adr lr, BSYM(ret_from_exception)
b do_DataAbort
+ UNWIND(.fnend )
ENDPROC(__dabt_usr)
.align 5
@@ -442,7 +485,10 @@ __irq_usr:
ldr r0, [tsk, #TI_PREEMPT]
str r8, [tsk, #TI_PREEMPT]
teq r0, r7
- strne r0, [r0, -r0]
+ itt ne
+ ARM( strne r0, [r0, -r0] )
+ THUMB( movne r0, #0 )
+ THUMB( strne r0, [r0] )
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
@@ -450,6 +496,7 @@ __irq_usr:
mov why, #0
b ret_to_user
+ UNWIND(.fnend )
ENDPROC(__irq_usr)
.ltorg
@@ -465,16 +512,23 @@ __und_usr:
@
@ r0 - instruction
@
- adr r9, ret_from_exception
- adr lr, __und_usr_unknown
+ adr r9, BSYM(ret_from_exception)
+ adr lr, BSYM(__und_usr_unknown)
tst r3, #PSR_T_BIT @ Thumb mode?
+ itet eq
subeq r4, r2, #4 @ ARM instr at LR - 4
subne r4, r2, #2 @ Thumb instr at LR - 2
1: ldreqt r0, [r4]
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ reveq r0, r0 @ little endian instruction
+#endif
beq call_fpe
@ Thumb instruction
#if __LINUX_ARM_ARCH__ >= 7
-2: ldrht r5, [r4], #2
+2:
+ ARM( ldrht r5, [r4], #2 )
+ THUMB( ldrht r5, [r4] )
+ THUMB( add r4, r4, #2 )
and r0, r5, #0xf800 @ mask bits 111x x... .... ....
cmp r0, #0xe800 @ 32bit instruction if xx != 0
blo __und_usr_unknown
@@ -484,6 +538,7 @@ __und_usr:
#else
b __und_usr_unknown
#endif
+ UNWIND(.fnend )
ENDPROC(__und_usr)
@
@@ -554,6 +609,7 @@ call_fpe:
1:
#endif
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27
+ ite ne
tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
and r8, r0, #0x0f000000 @ mask out op-code bits
@@ -562,9 +618,11 @@ call_fpe:
moveq pc, lr
get_thread_info r10 @ get current thread
and r8, r0, #0x00000f00 @ mask out CP number
+ THUMB( lsr r8, r8, #8 )
mov r7, #1
add r6, r10, #TI_USED_CP
- strb r7, [r6, r8, lsr #8] @ set appropriate used_cp[]
+ ARM( strb r7, [r6, r8, lsr #8] ) @ set appropriate used_cp[]
+ THUMB( strb r7, [r6, r8] ) @ set appropriate used_cp[]
#ifdef CONFIG_IWMMXT
@ Test if we need to give access to iWMMXt coprocessors
ldr r5, [r10, #TI_FLAGS]
@@ -572,36 +630,38 @@ call_fpe:
movcss r7, r5, lsr #(TIF_USING_IWMMXT + 1)
bcs iwmmxt_task_enable
#endif
- add pc, pc, r8, lsr #6
- mov r0, r0
-
- mov pc, lr @ CP#0
- b do_fpe @ CP#1 (FPE)
- b do_fpe @ CP#2 (FPE)
- mov pc, lr @ CP#3
+ ARM( add pc, pc, r8, lsr #6 )
+ THUMB( lsl r8, r8, #2 )
+ THUMB( add pc, r8 )
+ nop
+
+ movw_pc lr @ CP#0
+ W(b) do_fpe @ CP#1 (FPE)
+ W(b) do_fpe @ CP#2 (FPE)
+ movw_pc lr @ CP#3
#ifdef CONFIG_CRUNCH
b crunch_task_enable @ CP#4 (MaverickCrunch)
b crunch_task_enable @ CP#5 (MaverickCrunch)
b crunch_task_enable @ CP#6 (MaverickCrunch)
#else
- mov pc, lr @ CP#4
- mov pc, lr @ CP#5
- mov pc, lr @ CP#6
+ movw_pc lr @ CP#4
+ movw_pc lr @ CP#5
+ movw_pc lr @ CP#6
#endif
- mov pc, lr @ CP#7
- mov pc, lr @ CP#8
- mov pc, lr @ CP#9
+ movw_pc lr @ CP#7
+ movw_pc lr @ CP#8
+ movw_pc lr @ CP#9
#ifdef CONFIG_VFP
- b do_vfp @ CP#10 (VFP)
- b do_vfp @ CP#11 (VFP)
+ W(b) do_vfp @ CP#10 (VFP)
+ W(b) do_vfp @ CP#11 (VFP)
#else
- mov pc, lr @ CP#10 (VFP)
- mov pc, lr @ CP#11 (VFP)
+ movw_pc lr @ CP#10 (VFP)
+ movw_pc lr @ CP#11 (VFP)
#endif
- mov pc, lr @ CP#12
- mov pc, lr @ CP#13
- mov pc, lr @ CP#14 (Debug)
- mov pc, lr @ CP#15 (Control)
+ movw_pc lr @ CP#12
+ movw_pc lr @ CP#13
+ movw_pc lr @ CP#14 (Debug)
+ movw_pc lr @ CP#15 (Control)
#ifdef CONFIG_NEON
.align 6
@@ -647,12 +707,14 @@ ENTRY(fp_enter)
.word no_fp
.previous
-no_fp: mov pc, lr
+ENTRY(no_fp)
+ mov pc, lr
+ENDPROC(no_fp)
__und_usr_unknown:
enable_irq
mov r0, sp
- adr lr, ret_from_exception
+ adr lr, BSYM(ret_from_exception)
b do_undefinstr
ENDPROC(__und_usr_unknown)
@@ -671,14 +733,18 @@ __pabt_usr:
enable_irq @ Enable interrupts
mov r1, sp @ regs
bl do_PrefetchAbort @ call abort handler
+ UNWIND(.fnend )
/* fall through */
/*
* This is the return code to user mode for abort handlers
*/
ENTRY(ret_from_exception)
+ UNWIND(.fnstart )
+ UNWIND(.cantunwind )
get_thread_info tsk
mov why, #0
b ret_to_user
+ UNWIND(.fnend )
ENDPROC(__pabt_usr)
ENDPROC(ret_from_exception)
@@ -688,19 +754,17 @@ ENDPROC(ret_from_exception)
* previous and next are guaranteed not to be the same.
*/
ENTRY(__switch_to)
+ UNWIND(.fnstart )
+ UNWIND(.cantunwind )
add ip, r1, #TI_CPU_SAVE
ldr r3, [r2, #TI_TP_VALUE]
- stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack
+ ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
+ THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
+ THUMB( str sp, [ip], #4 )
+ THUMB( str lr, [ip], #4 )
#ifdef CONFIG_MMU
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
-#if __LINUX_ARM_ARCH__ >= 6
-#ifdef CONFIG_CPU_32v6K
- clrex
-#else
- strex r5, r4, [ip] @ Clear exclusive monitor
-#endif
-#endif
#if defined(CONFIG_HAS_TLS_REG)
mcr p15, 0, r3, c13, c0, 3 @ set TLS register
#elif !defined(CONFIG_TLS_REG_EMUL)
@@ -715,8 +779,13 @@ ENTRY(__switch_to)
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
+ THUMB( mov ip, r4 )
mov r0, r5
- ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
+ ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
+ THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
+ THUMB( ldr sp, [ip], #4 )
+ THUMB( ldr pc, [ip] )
+ UNWIND(.fnend )
ENDPROC(__switch_to)
__INIT
@@ -750,6 +819,7 @@ ENDPROC(__switch_to)
* if your compiled code is not going to use the new instructions for other
* purpose.
*/
+ THUMB( .arm )
.macro usr_ret, reg
#ifdef CONFIG_ARM_THUMB
@@ -921,6 +991,7 @@ kuser_cmpxchg_fixup:
#endif
1: ldrex r3, [r2]
subs r3, r3, r0
+ it eq
strexeq r3, r1, [r2]
teqeq r3, #1
beq 1b
@@ -1001,6 +1072,7 @@ __kuser_helper_version: @ 0xffff0ffc
.globl __kuser_helper_end
__kuser_helper_end:
+ THUMB( .thumb )
/*
* Vector stubs.
@@ -1035,17 +1107,23 @@ vector_\name:
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
- eor r0, r0, #(\mode ^ SVC_MODE)
+ eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f
+ THUMB( adr r0, 1f )
+ THUMB( ldr lr, [r0, lr, lsl #2] )
mov r0, sp
- ldr lr, [pc, lr, lsl #2]
+ ARM( ldr lr, [pc, lr, lsl #2] )
movs pc, lr @ branch to handler in SVC mode
ENDPROC(vector_\name)
+
+ .align 2
+ @ handler addresses follow this label
+1:
.endm
.globl __stubs_start
@@ -1183,14 +1261,16 @@ __stubs_end:
.globl __vectors_start
__vectors_start:
- swi SYS_ERROR0
- b vector_und + stubs_offset
- ldr pc, .LCvswi + stubs_offset
- b vector_pabt + stubs_offset
- b vector_dabt + stubs_offset
- b vector_addrexcptn + stubs_offset
- b vector_irq + stubs_offset
- b vector_fiq + stubs_offset
+ ARM( swi SYS_ERROR0 )
+ THUMB( svc #0 )
+ THUMB( nop )
+ W(b) vector_und + stubs_offset
+ W(ldr) pc, .LCvswi + stubs_offset
+ W(b) vector_pabt + stubs_offset
+ W(b) vector_dabt + stubs_offset
+ W(b) vector_addrexcptn + stubs_offset
+ W(b) vector_irq + stubs_offset
+ W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 159d0416f270..a68def8c9237 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -11,6 +11,7 @@
#include <asm/unistd.h>
#include <asm/ftrace.h>
#include <mach/entry-macro.S>
+#include <asm/unwind.h>
#include "entry-header.S"
@@ -22,6 +23,8 @@
* stack.
*/
ret_fast_syscall:
+ UNWIND(.fnstart )
+ UNWIND(.cantunwind )
disable_irq @ disable interrupts
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK
@@ -30,14 +33,8 @@ ret_fast_syscall:
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
- @ fast_restore_user_regs
- ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr
- ldr lr, [sp, #S_OFF + S_PC]! @ get pc
- msr spsr_cxsf, r1 @ save in spsr_svc
- ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
- mov r0, r0
- add sp, sp, #S_FRAME_SIZE - S_PC
- movs pc, lr @ return & move spsr_svc into cpsr
+ restore_user_regs fast = 1, offset = S_OFF
+ UNWIND(.fnend )
/*
* Ok, we need to do extra processing, enter the slow path.
@@ -69,14 +66,11 @@ no_work_pending:
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
- @ slow_restore_user_regs
- ldr r1, [sp, #S_PSR] @ get calling cpsr
- ldr lr, [sp, #S_PC]! @ get pc
- msr spsr_cxsf, r1 @ save in spsr_svc
- ldmdb sp, {r0 - lr}^ @ get calling r0 - lr
- mov r0, r0
- add sp, sp, #S_FRAME_SIZE - S_PC
- movs pc, lr @ return & move spsr_svc into cpsr
+#ifdef CONFIG_ARM_ERRATUM_451034
+ dmb
+#endif
+
+ restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user)
/*
@@ -176,14 +170,20 @@ ftrace_stub:
.align 5
ENTRY(vector_swi)
+#ifdef CONFIG_CPU_V7M
+ v7m_exception_entry
+#else
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
- add r8, sp, #S_PC
- stmdb r8, {sp, lr}^ @ Calling sp, lr
+ ARM( add r8, sp, #S_PC )
+ ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
+ THUMB( mov r8, sp )
+ THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
+#endif
zero_fp
/*
@@ -198,6 +198,7 @@ ENTRY(vector_swi)
*/
#ifdef CONFIG_ARM_THUMB
tst r8, #PSR_T_BIT
+ ite ne
movne r10, #0 @ no thumb OABI emulation
ldreq r10, [lr, #-4] @ get SWI instruction
#else
@@ -206,6 +207,9 @@ ENTRY(vector_swi)
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#endif
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ rev r10, r10 @ little endian instruction
+#endif
#elif defined(CONFIG_AEABI)
@@ -253,6 +257,7 @@ ENTRY(vector_swi)
* get the old ABI syscall table address.
*/
bics r10, r10, #0xff000000
+ itt ne
eorne scno, r10, #__NR_OABI_SYSCALL_BASE
ldrne tbl, =sys_oabi_call_table
#elif !defined(CONFIG_AEABI)
@@ -265,7 +270,8 @@ ENTRY(vector_swi)
bne __sys_trace
cmp scno, #NR_syscalls @ check upper syscall limit
- adr lr, ret_fast_syscall @ return address
+ adr lr, BSYM(ret_fast_syscall) @ return address
+ it cc
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
add r1, sp, #S_OFF
@@ -286,16 +292,23 @@ __sys_trace:
mov r0, #0 @ trace entry [IP = 0]
bl syscall_trace
- adr lr, __sys_trace_return @ return address
+ adr lr, BSYM(__sys_trace_return) @ return address
mov scno, r0 @ syscall number (possibly new)
- add r1, sp, #S_R0 + S_OFF @ pointer to regs
+ add r1, sp, #S_OFF @ pointer to regs
cmp scno, #NR_syscalls @ check upper syscall limit
+ itt cc
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
b 2b
__sys_trace_return:
+#ifdef CONFIG_CPU_V7M
+ @ S_R0 not at the beginning of struct pt_regs
+ add sp, #S_OFF
+ str r0, [sp, #S_R0] @ save returned r0
+#else
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
+#endif
mov r2, scno
mov r1, sp
mov r0, #1 @ trace exit [IP = 1]
@@ -335,11 +348,14 @@ ENTRY(sys_call_table)
sys_syscall:
bic scno, r0, #__NR_OABI_SYSCALL_BASE
cmp scno, #__NR_syscall - __NR_SYSCALL_BASE
+ it ne
cmpne scno, #NR_syscalls @ check range
+ itttt lo
stmloia sp, {r5, r6} @ shuffle args
movlo r0, r1
movlo r1, r2
movlo r2, r3
+ itt lo
movlo r3, r4
ldrlo pc, [tbl, scno, lsl #2]
b sys_ni_syscall
@@ -393,12 +409,14 @@ ENDPROC(sys_sigaltstack_wrapper)
sys_statfs64_wrapper:
teq r1, #88
+ it eq
moveq r1, #84
b sys_statfs64
ENDPROC(sys_statfs64_wrapper)
sys_fstatfs64_wrapper:
teq r1, #88
+ it eq
moveq r1, #84
b sys_fstatfs64
ENDPROC(sys_fstatfs64_wrapper)
@@ -410,6 +428,7 @@ ENDPROC(sys_fstatfs64_wrapper)
sys_mmap2:
#if PAGE_SHIFT > 12
tst r5, #PGOFF_MASK
+ ittt eq
moveq r5, r5, lsr #PAGE_SHIFT - 12
streq r5, [sp, #4]
beq do_mmap2
@@ -422,7 +441,9 @@ sys_mmap2:
ENDPROC(sys_mmap2)
ENTRY(pabort_ifar)
+#ifndef CONFIG_CPU_V7M
mrc p15, 0, r0, cr6, cr0, 2
+#endif
ENTRY(pabort_noifar)
mov pc, lr
ENDPROC(pabort_ifar)
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 87ab4e157997..1b0a2684a502 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -26,7 +26,7 @@
* The SWI code relies on the fact that R0 is at the bottom of the stack
* (due to slow/fast restore user regs).
*/
-#if S_R0 != 0
+#if S_R0 != 0 && !defined(CONFIG_CPU_V7M)
#error "Please fix"
#endif
@@ -36,11 +36,6 @@
#endif
.endm
- .macro get_thread_info, rd
- mov \rd, sp, lsr #13
- mov \rd, \rd, lsl #13
- .endm
-
.macro alignment_trap, rtemp
#ifdef CONFIG_ALIGNMENT_TRAP
ldr \rtemp, .LCcralign
@@ -49,6 +44,220 @@
#endif
.endm
+#ifdef CONFIG_CPU_V7M
+/*
+ * ARMv7-M exception entry/exit macros.
+ *
+ * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
+ * automatically saved on the current stack (32 words) before
+ * switching to the exception stack (SP_main). The order of struct
+ * pt_regs members was changed to take advantage of the automatic
+ * state saving.
+ *
+ * If exception is taken while in user mode, SP_main is
+ * empty. Otherwise, SP_main is aligned to 64 bit automatically
+ * (CCR.STKALIGN set).
+ *
+ * Linux assumes that the interrupts are disabled when entering an
+ * exception handler and it may BUG if this is not the case. Interrupts
+ * are disabled during entry and reenabled in the exit macro.
+ *
+ * The v7m_exception_entry macro preserves the original r0-r5, r7 for
+ * the system call arguments.
+ *
+ * v7_exception_fast_exit is used when returning from interrupts.
+ *
+ * v7_exception_slow_exit is used when returning from SVC or PendSV.
+ * When returning to kernel mode, we don't return from exception.
+ */
+ .macro v7m_exception_entry
+ cpsid i
+ cmp lr, #0xfffffffd @ check the return stack
+ beq 1f @ exception on process stack
+ add r12, sp, #32 @ MSP before exception
+ stmdb sp!, {r4-r12, lr} @ push unsaved registers
+ b 2f
+1:
+ mrs r12, psp @ get the process stack
+ sub sp, #S_FRAME_SIZE
+ stmia sp, {r4-r12, lr} @ push unsaved registers
+ ldmia r12, {r0-r3, r6, r8-r10} @ load automatically saved registers
+ add r12, sp, #S_R0
+ stmia r12, {r0-r3, r6, r8-r10} @ fill in the rest of struct pt_regs
+2:
+ .endm
+
+ .macro v7m_exception_fast_exit
+ clrex @ clear the exclusive monitor
+ ldmia sp!, {r4-r12, lr} @ restore previously saved state
+ cmp lr, #0xfffffffd @ check the return stack
+ it eq
+ addeq sp, #32 @ returning to PSP, just restore MSP
+ cpsie i
+ bx lr
+ .endm
+
+ .macro v7m_exception_slow_exit ret_r0
+ clrex @ clear the exclusive monitor
+ cpsid i
+ ldr lr, [sp, #S_EXC_LR] @ read exception LR
+ cmp lr, #0xfffffffd @ check the return stack
+ beq 1f @ returning to PSP
+ @ Prepare the MSP stack
+ ldmia sp, {r4-r11} @ restore previously saved state
+ ldr lr, [sp, #S_PC]
+ add sp, #S_R0
+ ldmia sp, {r0-r3, r12} @ restore the rest of registers
+ add sp, #S_FRAME_SIZE-S_R0 @ restore the stack pointer
+ cpsie i
+ bx lr
+1:
+ @ Prepare the PSP stack
+ ldr r12, [sp, #S_SP] @ read original PSP
+ .if \ret_r0
+ add r11, sp, #S_R1
+ ldmia r11, {r1-r7} @ read state saved on MSP (r0 preserved)
+ .else
+ add r11, sp, #S_R0
+ ldmia r11, {r0-r7} @ read state saved on MSP
+ .endif
+ msr psp, r12 @ restore PSP
+ stmia r12, {r0-r7} @ restore saved state to PSP
+ ldmia sp, {r4-r11} @ restore previously saved state
+ add sp, #S_FRAME_SIZE @ restore the original MSP
+ cpsie i
+ bx lr
+ .endm
+#endif /* CONFIG_CPU_V7M */
+
+ @
+ @ Store/load the USER SP and LR registers by switching to the SYS
+ @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
+ @ available. Should only be called from SVC mode
+ @
+ .macro store_user_sp_lr, rd, rtemp, offset = 0
+ mrs \rtemp, cpsr
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch to the SYS mode
+
+ str sp, [\rd, #\offset] @ save sp_usr
+ str lr, [\rd, #\offset + 4] @ save lr_usr
+
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch back to the SVC mode
+ .endm
+
+ .macro load_user_sp_lr, rd, rtemp, offset = 0
+ mrs \rtemp, cpsr
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch to the SYS mode
+
+ ldr sp, [\rd, #\offset] @ load sp_usr
+ ldr lr, [\rd, #\offset + 4] @ load lr_usr
+
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch back to the SVC mode
+ .endm
+
+#ifndef CONFIG_THUMB2_KERNEL
+ .macro svc_exit, rpsr
+ msr spsr_cxsf, \rpsr
+#if defined(CONFIG_CPU_32v6K)
+ clrex @ clear the exclusive monitor
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+#elif defined (CONFIG_CPU_V6)
+ ldr r0, [sp]
+ strex r1, r2, [sp] @ clear the exclusive monitor
+ ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr
+#else
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+#endif
+ .endm
+
+ .macro restore_user_regs, fast = 0, offset = 0
+ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
+ ldr lr, [sp, #\offset + S_PC]! @ get pc
+ msr spsr_cxsf, r1 @ save in spsr_svc
+#if defined(CONFIG_CPU_32v6K)
+ clrex @ clear the exclusive monitor
+#elif defined (CONFIG_CPU_V6)
+ strex r1, r2, [sp] @ clear the exclusive monitor
+#endif
+ .if \fast
+ ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
+ .else
+ ldmdb sp, {r0 - lr}^ @ get calling r0 - lr
+ .endif
+ add sp, sp, #S_FRAME_SIZE - S_PC
+ movs pc, lr @ return & move spsr_svc into cpsr
+ .endm
+
+ .macro get_thread_info, rd
+ mov \rd, sp, lsr #13
+ mov \rd, \rd, lsl #13
+ .endm
+
+ @
+ @ 32-bit wide "mov pc, reg"
+ @
+ .macro movw_pc, reg
+ mov pc, \reg
+ .endm
+#else /* CONFIG_THUMB2_KERNEL */
+ .macro svc_exit, rpsr
+ clrex @ clear the exclusive monitor
+ ldr r0, [sp, #S_SP] @ top of the stack
+ ldr r1, [sp, #S_PC] @ return address
+ tst r0, #4 @ orig stack 8-byte aligned?
+ stmdb r0, {r1, \rpsr} @ rfe context
+ ldmia sp, {r0 - r12}
+ ldr lr, [sp, #S_LR]
+ ite eq
+ addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned
+ addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned
+ rfeia sp!
+ .endm
+
+#ifdef CONFIG_CPU_V7M
+ .macro restore_user_regs, fast = 0, offset = 0
+ .if \offset
+ add sp, #\offset
+ .endif
+ v7m_exception_slow_exit ret_r0 = \fast
+ .endm
+#else /* !CONFIG_CPU_V7M */
+ .macro restore_user_regs, fast = 0, offset = 0
+ clrex @ clear the exclusive monitor
+ mov r2, sp
+ load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr
+ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
+ ldr lr, [sp, #\offset + S_PC] @ get pc
+ add sp, sp, #\offset + S_SP
+ msr spsr_cxsf, r1 @ save in spsr_svc
+ .if \fast
+ ldmdb sp, {r1 - r12} @ get calling r1 - r12
+ .else
+ ldmdb sp, {r0 - r12} @ get calling r0 - r12
+ .endif
+ add sp, sp, #S_FRAME_SIZE - S_SP
+ movs pc, lr @ return & move spsr_svc into cpsr
+ .endm
+#endif /* CONFIG_CPU_V7M */
+
+ .macro get_thread_info, rd
+ mov \rd, sp
+ lsr \rd, \rd, #13
+ mov \rd, \rd, lsl #13
+ .endm
+
+ @
+ @ 32-bit wide "mov pc, reg"
+ @
+ .macro movw_pc, reg
+ mov pc, \reg
+ nop
+ .endm
+#endif /* CONFIG_THUMB2_KERNEL */
/*
* These are the registers used in the syscall handler, and allow us to
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
new file mode 100644
index 000000000000..ffa8be3477db
--- /dev/null
+++ b/arch/arm/kernel/entry-v7m.S
@@ -0,0 +1,124 @@
+/*
+ * linux/arch/arm/kernel/entry-v7m.S
+ *
+ * Copyright (C) 2008 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Low-level vector interface routines for the ARMv7-M architecture
+ */
+#include <asm/memory.h>
+#include <asm/glue.h>
+#include <asm/thread_notify.h>
+
+#include <mach/entry-macro.S>
+
+#include "entry-header.S"
+
+#ifdef CONFIG_PREEMPT
+#error "CONFIG_PREEMPT not supported on the current ARMv7M implementation"
+#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+#error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation"
+#endif
+
+__invalid_entry:
+ v7m_exception_entry
+ mov r0, sp
+ bl __show_regs
+1: b 1b
+ENDPROC(__invalid_entry)
+
+__irq_entry:
+ v7m_exception_entry
+
+ @
+ @ Invoke the IRQ handler
+ @
+ mrs r0, ipsr
+ and r0, #0xff
+ sub r0, #16 @ IRQ number
+ mov r1, sp
+ @ routine called with r0 = irq number, r1 = struct pt_regs *
+ bl asm_do_IRQ
+
+ @
+ @ Check for any pending work if returning to user
+ @
+ ldr lr, [sp, #S_EXC_LR]
+ cmp lr, #0xfffffffd @ check the return stack
+ bne 2f @ returning to kernel
+ get_thread_info tsk
+ ldr r1, [tsk, #TI_FLAGS]
+ tst r1, #_TIF_WORK_MASK
+ beq 2f @ no work pending
+ ldr r1, =0xe000ed04 @ ICSR
+ mov r0, #1 << 28 @ ICSR.PENDSVSET
+ str r0, [r1] @ raise PendSV
+
+2:
+ v7m_exception_fast_exit
+ENDPROC(__irq_entry)
+
+__pendsv_entry:
+ v7m_exception_entry
+
+ ldr r1, =0xe000ed04 @ ICSR
+ mov r0, #1 << 27 @ ICSR.PENDSVCLR
+ str r0, [r1] @ clear PendSV
+
+ @ execute the pending work, including reschedule
+ get_thread_info tsk
+ mov why, #0
+ b ret_to_user
+ENDPROC(__pendsv_entry)
+
+/*
+ * Register switch for ARMv7-M processors.
+ * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
+ * previous and next are guaranteed not to be the same.
+ */
+ENTRY(__switch_to)
+ add ip, r1, #TI_CPU_SAVE
+ stmia ip!, {r4 - sl, fp} @ Store most regs on stack
+ str sp, [ip], #4
+ str lr, [ip], #4
+ mov r5, r0
+ add r4, r2, #TI_CPU_SAVE
+ ldr r0, =thread_notify_head
+ mov r1, #THREAD_NOTIFY_SWITCH
+ bl atomic_notifier_call_chain
+ mov ip, r4
+ mov r0, r5
+ ldmia ip!, {r4 - sl, fp} @ Load all regs saved previously
+ ldr sp, [ip], #4
+ ldr pc, [ip]
+ENDPROC(__switch_to)
+
+ .data
+ .align 8
+/*
+ * Vector table (64 words => 256 bytes natural alignment)
+ */
+ENTRY(vector_table)
+ .long 0 @ 0 - Reset stack pointer
+ .long __invalid_entry @ 1 - Reset
+ .long __invalid_entry @ 2 - NMI
+ .long __invalid_entry @ 3 - HardFault
+ .long __invalid_entry @ 4 - MemManage
+ .long __invalid_entry @ 5 - BusFault
+ .long __invalid_entry @ 6 - UsageFault
+ .long __invalid_entry @ 7 - Reserved
+ .long __invalid_entry @ 8 - Reserved
+ .long __invalid_entry @ 9 - Reserved
+ .long __invalid_entry @ 10 - Reserved
+ .long vector_swi @ 11 - SVCall
+ .long __invalid_entry @ 12 - Debug Monitor
+ .long __invalid_entry @ 13 - Reserved
+ .long __pendsv_entry @ 14 - PendSV
+ .long __invalid_entry @ 15 - SysTick
+ .rept 64 - 16
+ .long __irq_entry @ 16..64 - External Interrupts
+ .endr
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 991952c644d1..1a4d5b4054ff 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -14,6 +14,7 @@
#define ATAG_CORE 0x54410001
#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
+ .align 2
.type __switch_data, %object
__switch_data:
.long __mmap_switched
@@ -24,7 +25,11 @@ __switch_data:
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
+#ifdef CONFIG_CPU_CP15
.long cr_alignment @ r7
+#else
+ .long 0 @ r7
+#endif
.long init_thread_union + THREAD_START_SP @ sp
/*
@@ -41,6 +46,7 @@ __mmap_switched:
ldmia r3!, {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment if needed
+ itttt ne
1: cmpne r5, r6
ldrne fp, [r4], #4
strne fp, [r5], #4
@@ -48,10 +54,13 @@ __mmap_switched:
mov fp, #0 @ Clear BSS (and zero fp)
1: cmp r6, r7
+ itt cc
strcc fp, [r6],#4
bcc 1b
- ldmia r3, {r4, r5, r6, r7, sp}
+ ARM( ldmia r3, {r4, r5, r6, r7, sp})
+ THUMB( ldmia r3, {r4, r5, r6, r7} )
+ THUMB( ldr sp, [r3, #16] )
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer
@@ -155,7 +164,8 @@ ENDPROC(__error)
*/
__lookup_processor_type:
adr r3, 3f
- ldmda r3, {r5 - r7}
+ ldmia r3, {r5 - r7}
+ add r3, r3, #8
sub r3, r3, r7 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
@@ -185,9 +195,10 @@ ENDPROC(lookup_processor_type)
* Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
* more information about the __proc_info and __arch_info structures.
*/
- .long __proc_info_begin
+ .align 2
+3: .long __proc_info_begin
.long __proc_info_end
-3: .long .
+4: .long .
.long __arch_info_begin
.long __arch_info_end
@@ -203,11 +214,12 @@ ENDPROC(lookup_processor_type)
* r5 = mach_info pointer in physical address space
*/
__lookup_machine_type:
- adr r3, 3b
+ adr r3, 4b
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
+#ifndef CONFIG_NAKED_BOOT
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
@@ -216,6 +228,10 @@ __lookup_machine_type:
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
+#else
+ ldr r1, [r5, #MACHINFO_TYPE] @ force our only machine type
+ mov pc, lr @ and we're done
+#endif
ENDPROC(__lookup_machine_type)
/*
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index cc87e1765ed2..07a0fa7bb7bd 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -34,12 +34,15 @@
*/
.section ".text.head", "ax"
ENTRY(stext)
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
-#ifndef CONFIG_CPU_CP15
- ldr r9, =CONFIG_PROCESSOR_ID
-#else
+#if defined(CONFIG_CPU_CP15)
mrc p15, 0, r9, c0, c0 @ get processor id
+#elif defined(CONFIG_CPU_V7M)
+ ldr r9, =0xe000ed00 @ CPUID register address
+ ldr r9, [r9]
+#else
+ ldr r9, =CONFIG_PROCESSOR_ID
#endif
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
@@ -50,8 +53,10 @@ ENTRY(stext)
ldr r13, __switch_data @ address to jump to after
@ the initialization is done
- adr lr, __after_proc_init @ return (PIC) address
- add pc, r10, #PROCINFO_INITFUNC
+ adr lr, BSYM(__after_proc_init) @ return (PIC) address
+ ARM( add pc, r10, #PROCINFO_INITFUNC )
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(stext)
/*
@@ -59,7 +64,10 @@ ENDPROC(stext)
*/
__after_proc_init:
#ifdef CONFIG_CPU_CP15
- mrc p15, 0, r0, c1, c0, 0 @ read control reg
+ /*
+ * CP15 system control register value returned in r0 from
+ * the CPU init function.
+ */
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
#else
@@ -82,7 +90,8 @@ __after_proc_init:
mcr p15, 0, r0, c1, c0, 0 @ write control reg
#endif /* CONFIG_CPU_CP15 */
- mov pc, r13 @ clear the BSS and jump
+ mov r3, r13
+ mov pc, r3 @ clear the BSS and jump
@ to start_kernel
ENDPROC(__after_proc_init)
.ltorg
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 21e17dc94cb5..fc9b3dee4013 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -76,7 +76,7 @@
*/
.section ".text.head", "ax"
ENTRY(stext)
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
@@ -97,8 +97,10 @@ ENTRY(stext)
*/
ldr r13, __switch_data @ address to jump to after
@ mmu has been enabled
- adr lr, __enable_mmu @ return (PIC) address
- add pc, r10, #PROCINFO_INITFUNC
+ adr lr, BSYM(__enable_mmu) @ return (PIC) address
+ ARM( add pc, r10, #PROCINFO_INITFUNC )
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(stext)
#if defined(CONFIG_SMP)
@@ -110,10 +112,11 @@ ENTRY(secondary_startup)
* the processor type - there is no need to check the machine type
* as it has already been validated by the primary processor.
*/
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type
movs r10, r5 @ invalid processor?
+ it eq
moveq r0, #'p' @ yes, error 'p'
beq __error
@@ -121,12 +124,15 @@ ENTRY(secondary_startup)
* Use the page tables supplied from __cpu_up.
*/
adr r4, __secondary_data
- ldmia r4, {r5, r7, r13} @ address to jump to after
+ ldmia r4, {r5, r7, r12} @ address to jump to after
sub r4, r4, r5 @ mmu has been enabled
ldr r4, [r7, r4] @ get secondary_data.pgdir
- adr lr, __enable_mmu @ return address
- add pc, r10, #PROCINFO_INITFUNC @ initialise processor
- @ (return control reg)
+ adr lr, BSYM(__enable_mmu) @ return address
+ mov r13, r12 @ __secondary_switched address
+ ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor
+ @ (return control reg)
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(secondary_startup)
/*
@@ -193,8 +199,8 @@ __turn_mmu_on:
mcr p15, 0, r0, c1, c0, 0 @ write control reg
mrc p15, 0, r3, c0, c0, 0 @ read id reg
mov r3, r3
- mov r3, r3
- mov pc, r13
+ mov r3, r13
+ mov pc, r3
ENDPROC(__turn_mmu_on)
@@ -235,7 +241,8 @@ __create_page_tables:
* will be removed by paging_init(). We use our current program
* counter to determine corresponding section base address.
*/
- mov r6, pc, lsr #20 @ start of kernel section
+ mov r6, pc
+ mov r6, r6, lsr #20 @ start of kernel section
orr r3, r7, r6, lsl #20 @ flags + kernel base
str r3, [r4, r6, lsl #2] @ identity mapping
@@ -250,6 +257,7 @@ __create_page_tables:
add r6, r4, r6, lsr #18
1: cmp r0, r6
add r3, r3, #1 << 20
+ it ls
strls r3, [r0], #4
bls 1b
@@ -293,6 +301,7 @@ __create_page_tables:
add r0, r4, r3
rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long)
cmp r3, #0x0800 @ limit to 512MB
+ it hi
movhi r3, #0x0800
add r6, r0, r3
ldr r3, [r8, #MACHINFO_PHYSIO]
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 2ecffb8dcf50..59aaad65824a 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -22,6 +22,7 @@
#include <asm/pgtable.h>
#include <asm/sections.h>
+#include <asm/unwind.h>
#ifdef CONFIG_XIP_KERNEL
/*
@@ -66,6 +67,24 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
char *secstrings,
struct module *mod)
{
+#ifdef CONFIG_ARM_UNWIND
+ Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+
+ for (s = sechdrs; s < sechdrs_end; s++) {
+ if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
+ mod->arch.unw_sec_init = s;
+ else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
+ mod->arch.unw_sec_devinit = s;
+ else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
+ mod->arch.unw_sec_core = s;
+ else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
+ mod->arch.sec_init_text = s;
+ else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
+ mod->arch.sec_devinit_text = s;
+ else if (strcmp(".text", secstrings + s->sh_name) == 0)
+ mod->arch.sec_core_text = s;
+ }
+#endif
return 0;
}
@@ -83,6 +102,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
unsigned long loc;
Elf32_Sym *sym;
s32 offset;
+ u32 upper, lower, sign, j1, j2;
offset = ELF32_R_SYM(rel->r_info);
if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
@@ -104,6 +124,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
loc = dstsec->sh_addr + rel->r_offset;
switch (ELF32_R_TYPE(rel->r_info)) {
+ case R_ARM_NONE:
+ /* ignore */
+ break;
+
case R_ARM_ABS32:
*(u32 *)loc += sym->st_value;
break;
@@ -145,6 +169,61 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
*(u32 *)loc &= 0xfff0f000;
*(u32 *)loc |= ((offset & 0xf000) << 4) |
(offset & 0x0fff);
+ case R_ARM_PREL31:
+ offset = *(u32 *)loc + sym->st_value - loc;
+ *(u32 *)loc = offset & 0x7fffffff;
+ break;
+
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ upper = *(u16 *)loc;
+ lower = *(u16 *)(loc + 2);
+
+ /*
+ * 25 bit signed address range (Thumb-2 BL and B.W
+ * instructions):
+ * S:I1:I2:imm10:imm11:0
+ * where:
+ * S = upper[10] = offset[24]
+ * I1 = ~(J1 ^ S) = offset[23]
+ * I2 = ~(J2 ^ S) = offset[22]
+ * imm10 = upper[9:0] = offset[21:12]
+ * imm11 = lower[10:0] = offset[11:1]
+ * J1 = lower[13]
+ * J2 = lower[11]
+ */
+ sign = (upper >> 10) & 1;
+ j1 = (lower >> 13) & 1;
+ j2 = (lower >> 11) & 1;
+ offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
+ ((~(j2 ^ sign) & 1) << 22) |
+ ((upper & 0x03ff) << 12) |
+ ((lower & 0x07ff) << 1);
+ if (offset & 0x01000000)
+ offset -= 0x02000000;
+ offset += sym->st_value - loc;
+
+ /* only Thumb addresses allowed (no interworking) */
+ if (!(offset & 1) ||
+ offset <= (s32)0xff000000 ||
+ offset >= (s32)0x01000000) {
+ printk(KERN_ERR
+ "%s: relocation out of range, section "
+ "%d reloc %d sym '%s'\n", module->name,
+ relindex, i, strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+
+ sign = (offset >> 24) & 1;
+ j1 = sign ^ (~(offset >> 23) & 1);
+ j2 = sign ^ (~(offset >> 22) & 1);
+ *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) |
+ ((offset >> 12) & 0x03ff));
+ *(u16 *)(loc + 2) = (u16)((lower & 0xd000) |
+ (j1 << 13) | (j2 << 11) |
+ ((offset >> 1) & 0x07ff));
+ upper = *(u16 *)loc;
+ lower = *(u16 *)(loc + 2);
break;
default:
@@ -165,14 +244,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
return -ENOEXEC;
}
+#ifdef CONFIG_ARM_UNWIND
+static void register_unwind_tables(struct module *mod)
+{
+ if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
+ mod->arch.unwind_init =
+ unwind_table_add(mod->arch.unw_sec_init->sh_addr,
+ mod->arch.unw_sec_init->sh_size,
+ mod->arch.sec_init_text->sh_addr,
+ mod->arch.sec_init_text->sh_size);
+ if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
+ mod->arch.unwind_devinit =
+ unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
+ mod->arch.unw_sec_devinit->sh_size,
+ mod->arch.sec_devinit_text->sh_addr,
+ mod->arch.sec_devinit_text->sh_size);
+ if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
+ mod->arch.unwind_core =
+ unwind_table_add(mod->arch.unw_sec_core->sh_addr,
+ mod->arch.unw_sec_core->sh_size,
+ mod->arch.sec_core_text->sh_addr,
+ mod->arch.sec_core_text->sh_size);
+}
+
+static void unregister_unwind_tables(struct module *mod)
+{
+ unwind_table_del(mod->arch.unwind_init);
+ unwind_table_del(mod->arch.unwind_devinit);
+ unwind_table_del(mod->arch.unwind_core);
+}
+#else
+static inline void register_unwind_tables(struct module *mod) { }
+static inline void unregister_unwind_tables(struct module *mod) { }
+#endif
+
int
module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *module)
{
+ register_unwind_tables(module);
return 0;
}
void
module_arch_cleanup(struct module *mod)
{
+ unregister_unwind_tables(mod);
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f884b85030b7..c06f0481163b 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -34,6 +34,7 @@
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/thread_notify.h>
+#include <asm/stacktrace.h>
#include <asm/mach/time.h>
static const char *processor_modes[] = {
@@ -434,6 +435,23 @@ asm( ".section .text\n"
" .size kernel_thread_helper, . - kernel_thread_helper\n"
" .previous");
+#ifdef CONFIG_ARM_UNWIND
+extern void kernel_thread_exit(long code);
+asm( ".section .text\n"
+" .align\n"
+" .type kernel_thread_exit, #function\n"
+"kernel_thread_exit:\n"
+" .fnstart\n"
+" .cantunwind\n"
+" bl do_exit\n"
+" nop\n"
+" .fnend\n"
+" .size kernel_thread_exit, . - kernel_thread_exit\n"
+" .previous");
+#else
+#define kernel_thread_exit do_exit
+#endif
+
/*
* Create a kernel thread.
*/
@@ -445,9 +463,13 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
regs.ARM_r1 = (unsigned long)arg;
regs.ARM_r2 = (unsigned long)fn;
- regs.ARM_r3 = (unsigned long)do_exit;
+ regs.ARM_r3 = (unsigned long)kernel_thread_exit;
regs.ARM_pc = (unsigned long)kernel_thread_helper;
- regs.ARM_cpsr = SVC_MODE;
+ regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
+#ifdef CONFIG_CPU_V7M
+ /* Return to Handler mode */
+ regs.ARM_EXC_lr = 0xfffffff1L;
+#endif
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
@@ -455,23 +477,21 @@ EXPORT_SYMBOL(kernel_thread);
unsigned long get_wchan(struct task_struct *p)
{
- unsigned long fp, lr;
- unsigned long stack_start, stack_end;
+ struct stackframe frame;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
- stack_start = (unsigned long)end_of_stack(p);
- stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-
- fp = thread_saved_fp(p);
+ frame.fp = thread_saved_fp(p);
+ frame.sp = thread_saved_sp(p);
+ frame.lr = 0; /* recovered from the stack */
+ frame.pc = thread_saved_pc(p);
do {
- if (fp < stack_start || fp > stack_end)
+ int ret = unwind_frame(&frame);
+ if (ret < 0)
return 0;
- lr = ((unsigned long *)fp)[-1];
- if (!in_sched_functions(lr))
- return lr;
- fp = *(unsigned long *) (fp - 12);
+ if (!in_sched_functions(frame.pc))
+ return frame.pc;
} while (count ++ < 16);
return 0;
}
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 89882a1d0187..a2ea3854cb3c 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -521,7 +521,13 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
return -EIO;
tmp = 0;
- if (off < sizeof(struct pt_regs))
+ if (off == PT_TEXT_ADDR)
+ tmp = tsk->mm->start_code;
+ else if (off == PT_DATA_ADDR)
+ tmp = tsk->mm->start_data;
+ else if (off == PT_TEXT_END_ADDR)
+ tmp = tsk->mm->end_code;
+ else if (off < sizeof(struct pt_regs))
tmp = get_user_reg(tsk, off >> 2);
return put_user(tmp, ret);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index d301a5385428..4d9b74a355a8 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/fs.h>
+#include <asm/unified.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/elf.h>
@@ -40,6 +41,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <asm/traps.h>
+#include <asm/unwind.h>
#include "compat.h"
#include "atags.h"
@@ -107,7 +109,9 @@ struct stack {
u32 und[3];
} ____cacheline_aligned;
+#ifndef CONFIG_CPU_V7M
static struct stack stacks[NR_CPUS];
+#endif
char elf_platform[ELF_PLATFORM_SIZE];
EXPORT_SYMBOL(elf_platform);
@@ -195,6 +199,12 @@ static const char *proc_arch[] = {
"?(17)",
};
+#ifdef CONFIG_CPU_V7M
+int cpu_architecture(void)
+{
+ return CPU_ARCH_ARMv7M;
+}
+#else
int cpu_architecture(void)
{
int cpu_arch;
@@ -214,7 +224,7 @@ int cpu_architecture(void)
* Register 0 and check for VMSAv7 or PMSAv7 */
asm("mrc p15, 0, %0, c0, c1, 4"
: "=r" (mmfr0));
- if ((mmfr0 & 0x0000000f) == 0x00000003 ||
+ if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
(mmfr0 & 0x000000f0) == 0x00000030)
cpu_arch = CPU_ARCH_ARMv7;
else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
@@ -227,6 +237,8 @@ int cpu_architecture(void)
return cpu_arch;
}
+#endif
+EXPORT_SYMBOL(cpu_architecture);
static void __init cacheid_init(void)
{
@@ -295,9 +307,15 @@ static void __init setup_processor(void)
cpu_cache = *list->cache;
#endif
+#ifdef CONFIG_CPU_V7M
+ printk("CPU: %s [%08x] revision %d (ARMv%sM)\n",
+ cpu_name, processor_id, (int)processor_id & 15,
+ proc_arch[cpu_architecture()]);
+#else
printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
proc_arch[cpu_architecture()], cr_alignment);
+#endif
sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
@@ -317,6 +335,7 @@ static void __init setup_processor(void)
*/
void cpu_init(void)
{
+#ifndef CONFIG_CPU_V7M
unsigned int cpu = smp_processor_id();
struct stack *stk = &stacks[cpu];
@@ -326,26 +345,40 @@ void cpu_init(void)
}
/*
+ * Define the placement constraint for the inline asm directive below.
+ * In Thumb-2, msr with an immediate value is not allowed.
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+#define PLC "r"
+#else
+#define PLC "I"
+#endif
+
+ /*
* setup stacks for re-entrant exception handlers
*/
__asm__ (
"msr cpsr_c, %1\n\t"
- "add sp, %0, %2\n\t"
+ "add r14, %0, %2\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %3\n\t"
- "add sp, %0, %4\n\t"
+ "add r14, %0, %4\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %5\n\t"
- "add sp, %0, %6\n\t"
+ "add r14, %0, %6\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %7"
:
: "r" (stk),
- "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
"I" (offsetof(struct stack, irq[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
"I" (offsetof(struct stack, abt[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+ PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
+#endif
}
static struct machine_desc * __init setup_machine(unsigned int nr)
@@ -685,6 +718,8 @@ void __init setup_arch(char **cmdline_p)
struct machine_desc *mdesc;
char *from = default_command_line;
+ unwind_init();
+
setup_processor();
mdesc = setup_machine(machine_arch_type);
machine_name = mdesc->name;
@@ -692,10 +727,12 @@ void __init setup_arch(char **cmdline_p)
if (mdesc->soft_reboot)
reboot_setup("s");
+#ifndef CONFIG_NAKED_BOOT
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
+#endif
/*
* If we have the old style parameters, convert them to
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 8f96922e2827..ceb130e0e9c2 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -426,9 +426,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
*/
thumb = handler & 1;
- if (thumb)
+ if (thumb) {
cpsr |= PSR_T_BIT;
- else
+#if __LINUX_ARM_ARCH__ >= 7
+ /* clear the If-Then Thumb-2 execution state */
+ cpsr &= ~PSR_IT_MASK;
+#endif
+ } else
cpsr &= ~PSR_T_BIT;
}
#endif
@@ -542,7 +546,9 @@ static inline void restart_syscall(struct pt_regs *regs)
regs->ARM_r0 = -EINTR;
return;
}
+#ifndef CONFIG_CPU_V7M
regs->ARM_r0 = regs->ARM_ORIG_r0;
+#endif
regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 55fa7ff96a3e..fb671ac0e816 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -60,6 +60,9 @@ enum ipi_msg_type {
IPI_CALL_FUNC,
IPI_CALL_FUNC_SINGLE,
IPI_CPU_STOP,
+#ifdef CONFIG_CPU_NO_CACHE_BCAST
+ IPI_DMA_CACHE,
+#endif
};
int __cpuinit __cpu_up(unsigned int cpu)
@@ -93,6 +96,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET);
*pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
+ flush_pmd_entry(pmd);
/*
* We need to tell the secondary core where to find
@@ -130,6 +134,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
secondary_data.pgdir = 0;
*pmd = __pmd(0);
+ clean_pmd_entry(pmd);
pgd_free(&init_mm, pgd);
if (ret) {
@@ -424,6 +429,10 @@ static void ipi_cpu_stop(unsigned int cpu)
cpu_relax();
}
+#ifdef CONFIG_CPU_NO_CACHE_BCAST
+static void ipi_dma_cache_op(unsigned int cpu);
+#endif
+
/*
* Main handler for inter-processor interrupts
*
@@ -483,6 +492,12 @@ asmlinkage void __exception do_IPI(struct pt_regs *regs)
ipi_cpu_stop(cpu);
break;
+#ifdef CONFIG_CPU_NO_CACHE_BCAST
+ case IPI_DMA_CACHE:
+ ipi_dma_cache_op(cpu);
+ break;
+#endif
+
default:
printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
cpu, nextmsg);
@@ -593,19 +608,19 @@ static inline void ipi_flush_tlb_kernel_range(void *arg)
local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
}
-void flush_tlb_all(void)
+void smp_flush_tlb_all(void)
{
on_each_cpu(ipi_flush_tlb_all, NULL, 1);
}
-void flush_tlb_mm(struct mm_struct *mm)
+void smp_flush_tlb_mm(struct mm_struct *mm)
{
cpumask_t mask = mm->cpu_vm_mask;
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mask);
}
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
struct tlb_args ta;
@@ -616,7 +631,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mask);
}
-void flush_tlb_kernel_page(unsigned long kaddr)
+void smp_flush_tlb_kernel_page(unsigned long kaddr)
{
struct tlb_args ta;
@@ -625,7 +640,7 @@ void flush_tlb_kernel_page(unsigned long kaddr)
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
}
-void flush_tlb_range(struct vm_area_struct *vma,
+void smp_flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
@@ -638,7 +653,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mask);
}
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
struct tlb_args ta;
@@ -647,3 +662,123 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
}
+
+#ifdef CONFIG_CPU_NO_CACHE_BCAST
+/*
+ * DMA cache maintenance operations on SMP if the automatic hardware
+ * broadcasting is not available
+ */
+struct smp_dma_cache_struct {
+ int type;
+ const void *start;
+ const void *end;
+ cpumask_t unfinished;
+};
+
+static struct smp_dma_cache_struct *smp_dma_cache_data;
+static DEFINE_RWLOCK(smp_dma_cache_data_lock);
+static DEFINE_SPINLOCK(smp_dma_cache_lock);
+
+static void local_dma_cache_op(int type, const void *start, const void *end)
+{
+ switch (type) {
+ case SMP_DMA_CACHE_INV:
+ dmac_inv_range(start, end);
+ break;
+ case SMP_DMA_CACHE_CLEAN:
+ dmac_clean_range(start, end);
+ break;
+ case SMP_DMA_CACHE_FLUSH:
+ dmac_flush_range(start, end);
+ break;
+ default:
+ printk(KERN_CRIT "CPU%u: Unknown SMP DMA cache type %d\n",
+ smp_processor_id(), type);
+ }
+}
+
+/*
+ * This function must be executed with interrupts disabled.
+ */
+static void ipi_dma_cache_op(unsigned int cpu)
+{
+ read_lock(&smp_dma_cache_data_lock);
+
+ /* check for spurious IPI */
+ if ((smp_dma_cache_data == NULL) ||
+ (!cpu_isset(cpu, smp_dma_cache_data->unfinished)))
+ goto out;
+ local_dma_cache_op(smp_dma_cache_data->type,
+ smp_dma_cache_data->start, smp_dma_cache_data->end);
+ cpu_clear(cpu, smp_dma_cache_data->unfinished);
+ out:
+ read_unlock(&smp_dma_cache_data_lock);
+}
+
+/*
+ * Execute the DMA cache operations on all online CPUs. This function
+ * can be called with interrupts disabled or from interrupt context.
+ */
+static void __smp_dma_cache_op(int type, const void *start, const void *end)
+{
+ struct smp_dma_cache_struct data;
+ cpumask_t callmap = cpu_online_map;
+ unsigned int cpu = get_cpu();
+ unsigned long flags;
+
+ cpu_clear(cpu, callmap);
+ data.type = type;
+ data.start = start;
+ data.end = end;
+ data.unfinished = callmap;
+
+ /*
+ * If the spinlock cannot be acquired, other CPU is trying to
+ * send an IPI. If the interrupts are disabled, we have to
+ * poll for an incoming IPI.
+ */
+ while (!spin_trylock_irqsave(&smp_dma_cache_lock, flags)) {
+ if (irqs_disabled())
+ ipi_dma_cache_op(cpu);
+ }
+
+ write_lock(&smp_dma_cache_data_lock);
+ smp_dma_cache_data = &data;
+ write_unlock(&smp_dma_cache_data_lock);
+
+ if (!cpus_empty(callmap))
+ send_ipi_message(callmap, IPI_DMA_CACHE);
+ /* run the local operation in parallel with the other CPUs */
+ local_dma_cache_op(type, start, end);
+
+ while (!cpus_empty(data.unfinished))
+ barrier();
+
+ write_lock(&smp_dma_cache_data_lock);
+ smp_dma_cache_data = NULL;
+ write_unlock(&smp_dma_cache_data_lock);
+
+ spin_unlock_irqrestore(&smp_dma_cache_lock, flags);
+ put_cpu();
+}
+
+#define DMA_MAX_RANGE SZ_4K
+
+/*
+ * Split the cache range in smaller pieces if interrupts are enabled
+ * to reduce the latency caused by disabling the interrupts during the
+ * broadcast.
+ */
+void smp_dma_cache_op(int type, const void *start, const void *end)
+{
+ if (irqs_disabled() || (end - start <= DMA_MAX_RANGE))
+ __smp_dma_cache_op(type, start, end);
+ else {
+ const void *ptr;
+ for (ptr = start; ptr < end - DMA_MAX_RANGE;
+ ptr += DMA_MAX_RANGE)
+ __smp_dma_cache_op(type, ptr, ptr + DMA_MAX_RANGE);
+ __smp_dma_cache_op(type, ptr, end);
+ }
+}
+#endif
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index fc650f64df43..b371c54e548a 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -2,35 +2,60 @@
#include <linux/sched.h>
#include <linux/stacktrace.h>
-#include "stacktrace.h"
-
-int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
- int (*fn)(struct stackframe *, void *), void *data)
+#include <asm/stacktrace.h>
+
+#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+/*
+ * Unwind the current stack frame and store the new register values in the
+ * structure passed as argument. Unwinding is equivalent to a function return,
+ * hence the new PC value rather than LR should be used for backtrace.
+ *
+ * With framepointer enabled, a simple function prologue looks like this:
+ * mov ip, sp
+ * stmdb sp!, {fp, ip, lr, pc}
+ * sub fp, ip, #4
+ *
+ * A simple function epilogue looks like this:
+ * ldm sp, {fp, sp, pc}
+ *
+ * Note that with framepointer enabled, even the leaf functions have the same
+ * prologue and epilogue, therefore we can ignore the LR value in this case.
+ */
+int unwind_frame(struct stackframe *frame)
{
- struct stackframe *frame;
+ unsigned long high, low;
+ unsigned long fp = frame->fp;
- do {
- /*
- * Check current frame pointer is within bounds
- */
- if (fp < (low + 12) || fp + 4 >= high)
- break;
+ /* only go to a higher address on the stack */
+ low = frame->sp;
+ high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
- frame = (struct stackframe *)(fp - 12);
+ /* check current frame pointer is within bounds */
+ if (fp < (low + 12) || fp + 4 >= high)
+ return -EINVAL;
- if (fn(frame, data))
- break;
-
- /*
- * Update the low bound - the next frame must always
- * be at a higher address than the current frame.
- */
- low = fp + 4;
- fp = frame->fp;
- } while (fp);
+ /* restore the registers from the stack frame */
+ frame->fp = *(unsigned long *)(fp - 12);
+ frame->sp = *(unsigned long *)(fp - 8);
+ frame->pc = *(unsigned long *)(fp - 4);
return 0;
}
+#endif
+
+void walk_stackframe(struct stackframe *frame,
+ int (*fn)(struct stackframe *, void *), void *data)
+{
+ while (1) {
+ int ret;
+
+ if (fn(frame, data))
+ break;
+ ret = unwind_frame(frame);
+ if (ret < 0)
+ break;
+ }
+}
EXPORT_SYMBOL(walk_stackframe);
#ifdef CONFIG_STACKTRACE
@@ -44,7 +69,7 @@ static int save_trace(struct stackframe *frame, void *d)
{
struct stack_trace_data *data = d;
struct stack_trace *trace = data->trace;
- unsigned long addr = frame->lr;
+ unsigned long addr = frame->pc;
if (data->no_sched_functions && in_sched_functions(addr))
return 0;
@@ -61,11 +86,10 @@ static int save_trace(struct stackframe *frame, void *d)
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
struct stack_trace_data data;
- unsigned long fp, base;
+ struct stackframe frame;
data.trace = trace;
data.skip = trace->skip;
- base = (unsigned long)task_stack_page(tsk);
if (tsk != current) {
#ifdef CONFIG_SMP
@@ -76,14 +100,22 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
BUG();
#else
data.no_sched_functions = 1;
- fp = thread_saved_fp(tsk);
+ frame.fp = thread_saved_fp(tsk);
+ frame.sp = thread_saved_sp(tsk);
+ frame.lr = 0; /* recovered from the stack */
+ frame.pc = thread_saved_pc(tsk);
#endif
} else {
+ register unsigned long current_sp asm ("sp");
+
data.no_sched_functions = 0;
- asm("mov %0, fp" : "=r" (fp));
+ frame.fp = (unsigned long)__builtin_frame_address(0);
+ frame.sp = current_sp;
+ frame.lr = (unsigned long)__builtin_return_address(0);
+ frame.pc = (unsigned long)save_stack_trace_tsk;
}
- walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
+ walk_stackframe(&frame, save_trace, &data);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
diff --git a/arch/arm/kernel/stacktrace.h b/arch/arm/kernel/stacktrace.h
deleted file mode 100644
index e9fd20cb5662..000000000000
--- a/arch/arm/kernel/stacktrace.h
+++ /dev/null
@@ -1,9 +0,0 @@
-struct stackframe {
- unsigned long fp;
- unsigned long sp;
- unsigned long lr;
- unsigned long pc;
-};
-
-int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
- int (*fn)(struct stackframe *, void *), void *data);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index c68b44aa88d2..4cdc4a0bd02d 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -33,6 +33,7 @@
#include <asm/leds.h>
#include <asm/thread_info.h>
+#include <asm/stacktrace.h>
#include <asm/mach/time.h>
/*
@@ -55,14 +56,22 @@ EXPORT_SYMBOL(rtc_lock);
#ifdef CONFIG_SMP
unsigned long profile_pc(struct pt_regs *regs)
{
- unsigned long fp, pc = instruction_pointer(regs);
+ struct stackframe frame;
- if (in_lock_functions(pc)) {
- fp = regs->ARM_fp;
- pc = ((unsigned long *)fp)[-1];
- }
+ if (!in_lock_functions(regs->ARM_pc))
+ return regs->ARM_pc;
+
+ frame.fp = regs->ARM_fp;
+ frame.sp = regs->ARM_sp;
+ frame.lr = regs->ARM_lr;
+ frame.pc = regs->ARM_pc;
+ do {
+ int ret = unwind_frame(&frame);
+ if (ret < 0)
+ return 0;
+ } while (in_lock_functions(frame.pc));
- return pc;
+ return frame.pc;
}
EXPORT_SYMBOL(profile_pc);
#endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 79abc4ddc0cf..6977342aa139 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -27,6 +27,7 @@
#include <asm/system.h>
#include <asm/unistd.h>
#include <asm/traps.h>
+#include <asm/unwind.h>
#include "ptrace.h"
#include "signal.h"
@@ -61,6 +62,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long
dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
}
+#ifndef CONFIG_ARM_UNWIND
/*
* Stack pointers should always be within the kernels view of
* physical memory. If it is not there, then we can't dump
@@ -74,6 +76,7 @@ static int verify_stack(unsigned long sp)
return 0;
}
+#endif
/*
* Dump out the contents of some memory nicely...
@@ -150,13 +153,33 @@ static void dump_instr(struct pt_regs *regs)
set_fs(fs);
}
+#ifdef CONFIG_ARM_UNWIND
+static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
+{
+ unwind_backtrace(regs, tsk);
+}
+#else
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
- unsigned int fp;
+ unsigned int fp, mode;
int ok = 1;
printk("Backtrace: ");
- fp = regs->ARM_fp;
+
+ if (!tsk)
+ tsk = current;
+
+ if (regs) {
+ fp = regs->ARM_fp;
+ mode = processor_mode(regs);
+ } else if (tsk != current) {
+ fp = thread_saved_fp(tsk);
+ mode = 0x10;
+ } else {
+ asm("mov %0, fp" : "=r" (fp) : : "cc");
+ mode = 0x10;
+ }
+
if (!fp) {
printk("no frame pointer");
ok = 0;
@@ -168,29 +191,20 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
printk("\n");
if (ok)
- c_backtrace(fp, processor_mode(regs));
+ c_backtrace(fp, mode);
}
+#endif
void dump_stack(void)
{
- __backtrace();
+ dump_backtrace(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
- unsigned long fp;
-
- if (!tsk)
- tsk = current;
-
- if (tsk != current)
- fp = thread_saved_fp(tsk);
- else
- asm("mov %0, fp" : "=r" (fp) : : "cc");
-
- c_backtrace(fp, 0x10);
+ dump_backtrace(NULL, tsk);
barrier();
}
@@ -625,6 +639,14 @@ void __bad_xchg(volatile void *ptr, int size)
}
EXPORT_SYMBOL(__bad_xchg);
+void __bad_cmpxchg(volatile void *ptr, int size)
+{
+ printk("cmpxchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
+ __builtin_return_address(0), ptr, size);
+ BUG();
+}
+EXPORT_SYMBOL(__bad_cmpxchg);
+
/*
* A data abort trap was taken, but we did not handle the instruction.
* Try to abort the user program, or panic if it was the kernel.
@@ -707,6 +729,7 @@ void __init trap_init(void)
void __init early_trap_init(void)
{
+#ifndef CONFIG_CPU_V7M
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
@@ -731,4 +754,5 @@ void __init early_trap_init(void)
flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
+#endif
}
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
new file mode 100644
index 000000000000..39baf1128bfa
--- /dev/null
+++ b/arch/arm/kernel/unwind.c
@@ -0,0 +1,437 @@
+/*
+ * arch/arm/kernel/unwind.c
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Stack unwinding support for ARM
+ *
+ * An ARM EABI version of gcc is required to generate the unwind
+ * tables. For information about the structure of the unwind tables,
+ * see "Exception Handling ABI for the ARM Architecture" at:
+ *
+ * http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#include <asm/stacktrace.h>
+#include <asm/traps.h>
+#include <asm/unwind.h>
+
+/* Dummy functions to avoid linker complaints */
+void __aeabi_unwind_cpp_pr0(void)
+{
+};
+EXPORT_SYMBOL(__aeabi_unwind_cpp_pr0);
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+};
+EXPORT_SYMBOL(__aeabi_unwind_cpp_pr1);
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+};
+EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
+
+struct unwind_ctrl_block {
+ unsigned long vrs[16]; /* virtual register set */
+ unsigned long *insn; /* pointer to the current instructions word */
+ int entries; /* number of entries left to interpret */
+ int byte; /* current byte number in the instructions word */
+};
+
+enum regs {
+#ifdef CONFIG_THUMB2_KERNEL
+ FP = 7,
+#else
+ FP = 11,
+#endif
+ SP = 13,
+ LR = 14,
+ PC = 15
+};
+
+extern struct unwind_idx __start_unwind_idx[];
+extern struct unwind_idx __stop_unwind_idx[];
+
+static DEFINE_SPINLOCK(unwind_lock);
+static LIST_HEAD(unwind_tables);
+
+/* Convert a prel31 symbol to an absolute address */
+#define prel31_to_addr(ptr) \
+({ \
+ /* sign-extend to 32 bits */ \
+ long offset = (((long)*(ptr)) << 1) >> 1; \
+ (unsigned long)(ptr) + offset; \
+})
+
+/*
+ * Binary search in the unwind index. The entries entries are
+ * guaranteed to be sorted in ascending order by the linker.
+ */
+static struct unwind_idx *search_index(unsigned long addr,
+ struct unwind_idx *first,
+ struct unwind_idx *last)
+{
+ pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last);
+
+ if (addr < first->addr) {
+ pr_warning("unwind: Unknown symbol address %08lx\n", addr);
+ return NULL;
+ } else if (addr >= last->addr)
+ return last;
+
+ while (first < last - 1) {
+ struct unwind_idx *mid = first + ((last - first + 1) >> 1);
+
+ if (addr < mid->addr)
+ last = mid;
+ else
+ first = mid;
+ }
+
+ return first;
+}
+
+static struct unwind_idx *unwind_find_idx(unsigned long addr)
+{
+ struct unwind_idx *idx = NULL;
+ unsigned long flags;
+
+ pr_debug("%s(%08lx)\n", __func__, addr);
+
+ if (core_kernel_text(addr))
+ /* main unwind table */
+ idx = search_index(addr, __start_unwind_idx,
+ __stop_unwind_idx - 1);
+ else {
+ /* module unwind tables */
+ struct unwind_table *table;
+
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_for_each_entry(table, &unwind_tables, list) {
+ if (addr >= table->begin_addr &&
+ addr < table->end_addr) {
+ idx = search_index(addr, table->start,
+ table->stop - 1);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&unwind_lock, flags);
+ }
+
+ pr_debug("%s: idx = %p\n", __func__, idx);
+ return idx;
+}
+
+static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
+{
+ unsigned long ret;
+
+ if (ctrl->entries <= 0) {
+ pr_warning("unwind: Corrupt unwind table\n");
+ return 0;
+ }
+
+ ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+ if (ctrl->byte == 0) {
+ ctrl->insn++;
+ ctrl->entries--;
+ ctrl->byte = 3;
+ } else
+ ctrl->byte--;
+
+ return ret;
+}
+
+/*
+ * Execute the current unwind instruction.
+ */
+static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
+{
+ unsigned long insn = unwind_get_byte(ctrl);
+
+ pr_debug("%s: insn = %08lx\n", __func__, insn);
+
+ if ((insn & 0xc0) == 0x00)
+ ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
+ else if ((insn & 0xc0) == 0x40)
+ ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
+ else if ((insn & 0xf0) == 0x80) {
+ unsigned long mask;
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int load_sp, reg = 4;
+
+ insn = (insn << 8) | unwind_get_byte(ctrl);
+ mask = insn & 0x0fff;
+ if (mask == 0) {
+ pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
+ insn);
+ return -URC_FAILURE;
+ }
+
+ /* pop R4-R15 according to mask */
+ load_sp = mask & (1 << (13 - 4));
+ while (mask) {
+ if (mask & 1)
+ ctrl->vrs[reg] = *vsp++;
+ mask >>= 1;
+ reg++;
+ }
+ if (!load_sp)
+ ctrl->vrs[SP] = (unsigned long)vsp;
+ } else if ((insn & 0xf0) == 0x90 &&
+ (insn & 0x0d) != 0x0d)
+ ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
+ else if ((insn & 0xf0) == 0xa0) {
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int reg;
+
+ /* pop R4-R[4+bbb] */
+ for (reg = 4; reg <= 4 + (insn & 7); reg++)
+ ctrl->vrs[reg] = *vsp++;
+ if (insn & 0x80)
+ ctrl->vrs[14] = *vsp++;
+ ctrl->vrs[SP] = (unsigned long)vsp;
+ } else if (insn == 0xb0) {
+ if (ctrl->vrs[PC] == 0)
+ ctrl->vrs[PC] = ctrl->vrs[LR];
+ /* no further processing */
+ ctrl->entries = 0;
+ } else if (insn == 0xb1) {
+ unsigned long mask = unwind_get_byte(ctrl);
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int reg = 0;
+
+ if (mask == 0 || mask & 0xf0) {
+ pr_warning("unwind: Spare encoding %04lx\n",
+ (insn << 8) | mask);
+ return -URC_FAILURE;
+ }
+
+ /* pop R0-R3 according to mask */
+ while (mask) {
+ if (mask & 1)
+ ctrl->vrs[reg] = *vsp++;
+ mask >>= 1;
+ reg++;
+ }
+ ctrl->vrs[SP] = (unsigned long)vsp;
+ } else if (insn == 0xb2) {
+ unsigned long uleb128 = unwind_get_byte(ctrl);
+
+ ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+ } else {
+ pr_warning("unwind: Unhandled instruction %02lx\n", insn);
+ return -URC_FAILURE;
+ }
+
+ pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
+ ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
+
+ return URC_OK;
+}
+
+/*
+ * Unwind a single frame starting with *sp for the symbol at *pc. It
+ * updates the *pc and *sp with the new values.
+ */
+int unwind_frame(struct stackframe *frame)
+{
+ unsigned long high, low;
+ struct unwind_idx *idx;
+ struct unwind_ctrl_block ctrl;
+
+ /* only go to a higher address on the stack */
+ low = frame->sp;
+ high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
+
+ pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
+ frame->pc, frame->lr, frame->sp);
+
+ if (!kernel_text_address(frame->pc))
+ return -URC_FAILURE;
+
+ idx = unwind_find_idx(frame->pc);
+ if (!idx) {
+ pr_warning("unwind: Index not found %08lx\n", frame->pc);
+ return -URC_FAILURE;
+ }
+
+ ctrl.vrs[FP] = frame->fp;
+ ctrl.vrs[SP] = frame->sp;
+ ctrl.vrs[LR] = frame->lr;
+ ctrl.vrs[PC] = 0;
+
+ if (idx->insn == 1)
+ /* can't unwind */
+ return -URC_FAILURE;
+ else if ((idx->insn & 0x80000000) == 0)
+ /* prel31 to the unwind table */
+ ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
+ else if ((idx->insn & 0xff000000) == 0x80000000)
+ /* only personality routine 0 supported in the index */
+ ctrl.insn = &idx->insn;
+ else {
+ pr_warning("unwind: Unsupported personality routine %08lx in the index at %p\n",
+ idx->insn, idx);
+ return -URC_FAILURE;
+ }
+
+ /* check the personality routine */
+ if ((*ctrl.insn & 0xff000000) == 0x80000000) {
+ ctrl.byte = 2;
+ ctrl.entries = 1;
+ } else if ((*ctrl.insn & 0xff000000) == 0x81000000) {
+ ctrl.byte = 1;
+ ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
+ } else {
+ pr_warning("unwind: Unsupported personality routine %08lx at %p\n",
+ *ctrl.insn, ctrl.insn);
+ return -URC_FAILURE;
+ }
+
+ while (ctrl.entries > 0) {
+ int urc = unwind_exec_insn(&ctrl);
+ if (urc < 0)
+ return urc;
+ if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
+ return -URC_FAILURE;
+ }
+
+ if (ctrl.vrs[PC] == 0)
+ ctrl.vrs[PC] = ctrl.vrs[LR];
+
+ /* check for infinite loop */
+ if (frame->pc == ctrl.vrs[PC])
+ return -URC_FAILURE;
+
+ frame->fp = ctrl.vrs[FP];
+ frame->sp = ctrl.vrs[SP];
+ frame->lr = ctrl.vrs[LR];
+ frame->pc = ctrl.vrs[PC];
+
+ return URC_OK;
+}
+
+void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
+{
+ struct stackframe frame;
+ register unsigned long current_sp asm ("sp");
+
+ pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
+
+ if (!tsk)
+ tsk = current;
+
+ if (regs) {
+ frame.fp = regs->ARM_fp;
+ frame.sp = regs->ARM_sp;
+ frame.lr = regs->ARM_lr;
+ frame.pc = regs->ARM_pc;
+ } else if (tsk == current) {
+ frame.fp = (unsigned long)__builtin_frame_address(0);
+ frame.sp = current_sp;
+ frame.lr = (unsigned long)__builtin_return_address(0);
+ frame.pc = (unsigned long)unwind_backtrace;
+ } else {
+ /* task blocked in __switch_to */
+ frame.fp = thread_saved_fp(tsk);
+ frame.sp = thread_saved_sp(tsk);
+ /*
+ * The function calling __switch_to cannot be a leaf function
+ * so LR is recovered from the stack.
+ */
+ frame.lr = 0;
+ frame.pc = thread_saved_pc(tsk);
+ }
+
+ while (1) {
+ int urc;
+ unsigned long where = frame.pc;
+
+ urc = unwind_frame(&frame);
+ if (urc < 0)
+ break;
+ dump_backtrace_entry(where, frame.pc, frame.sp - 4);
+ }
+}
+
+struct unwind_table *unwind_table_add(unsigned long start, unsigned long size,
+ unsigned long text_addr,
+ unsigned long text_size)
+{
+ unsigned long flags;
+ struct unwind_idx *idx;
+ struct unwind_table *tab = kmalloc(sizeof(*tab), GFP_KERNEL);
+
+ pr_debug("%s(%08lx, %08lx, %08lx, %08lx)\n", __func__, start, size,
+ text_addr, text_size);
+
+ if (!tab)
+ return tab;
+
+ tab->start = (struct unwind_idx *)start;
+ tab->stop = (struct unwind_idx *)(start + size);
+ tab->begin_addr = text_addr;
+ tab->end_addr = text_addr + text_size;
+
+ /* Convert the symbol addresses to absolute values */
+ for (idx = tab->start; idx < tab->stop; idx++)
+ idx->addr = prel31_to_addr(&idx->addr);
+
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_add_tail(&tab->list, &unwind_tables);
+ spin_unlock_irqrestore(&unwind_lock, flags);
+
+ return tab;
+}
+
+void unwind_table_del(struct unwind_table *tab)
+{
+ unsigned long flags;
+
+ if (!tab)
+ return;
+
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_del(&tab->list);
+ spin_unlock_irqrestore(&unwind_lock, flags);
+
+ kfree(tab);
+}
+
+int __init unwind_init(void)
+{
+ struct unwind_idx *idx;
+
+ /* Convert the symbol addresses to absolute values */
+ for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
+ idx->addr = prel31_to_addr(&idx->addr);
+
+ pr_debug("unwind: ARM stack unwinding initialised\n");
+
+ return 0;
+}
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 00216071eaf7..433b1e4bf46a 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -80,6 +80,16 @@ SECTIONS
EXIT_TEXT
EXIT_DATA
*(.exitcall.exit)
+ *(.ARM.exidx.exit.text)
+ *(.ARM.extab.exit.text)
+#ifndef CONFIG_HOTPLUG_CPU
+ *(.ARM.exidx.cpuexit.text)
+ *(.ARM.extab.cpuexit.text)
+#endif
+#ifndef CONFIG_HOTPLUG
+ *(.ARM.exidx.devexit.text)
+ *(.ARM.extab.devexit.text)
+#endif
#ifndef CONFIG_MMU
*(.fixup)
*(__ex_table)
@@ -110,6 +120,23 @@ SECTIONS
_etext = .; /* End of text and rodata section */
+#ifdef CONFIG_ARM_UNWIND
+ /*
+ * Stack unwinding tables
+ */
+ . = ALIGN(8);
+ .ARM.unwind_idx : {
+ __start_unwind_idx = .;
+ *(.ARM.exidx*)
+ __stop_unwind_idx = .;
+ }
+ .ARM.unwind_tab : {
+ __start_unwind_tab = .;
+ *(.ARM.extab*)
+ __stop_unwind_tab = .;
+ }
+#endif
+
#ifdef CONFIG_XIP_KERNEL
__data_loc = ALIGN(4); /* location in binary */
. = PAGE_OFFSET + TEXT_OFFSET;
diff --git a/arch/arm/lib/ashldi3.S b/arch/arm/lib/ashldi3.S
index 1154d924080b..b18944b85e4b 100644
--- a/arch/arm/lib/ashldi3.S
+++ b/arch/arm/lib/ashldi3.S
@@ -41,9 +41,12 @@ ENTRY(__aeabi_llsl)
subs r3, r2, #32
rsb ip, r2, #32
+ itett mi
movmi ah, ah, lsl r2
movpl ah, al, lsl r3
- orrmi ah, ah, al, lsr ip
+ ARM( orrmi ah, ah, al, lsr ip )
+ THUMB( lsrmi r3, al, ip )
+ THUMB( orrmi ah, ah, r3 )
mov al, al, lsl r2
mov pc, lr
diff --git a/arch/arm/lib/ashrdi3.S b/arch/arm/lib/ashrdi3.S
index 9f8b35572f8c..0d5ace74dd9d 100644
--- a/arch/arm/lib/ashrdi3.S
+++ b/arch/arm/lib/ashrdi3.S
@@ -41,9 +41,12 @@ ENTRY(__aeabi_lasr)
subs r3, r2, #32
rsb ip, r2, #32
+ itett mi
movmi al, al, lsr r2
movpl al, ah, asr r3
- orrmi al, al, ah, lsl ip
+ ARM( orrmi al, al, ah, lsl ip )
+ THUMB( lslmi r3, ah, ip )
+ THUMB( orrmi al, al, r3 )
mov ah, ah, asr r2
mov pc, lr
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index b0951d0e8b2c..41c4d3561b8f 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -28,7 +28,7 @@ ENTRY(__backtrace)
ENTRY(c_backtrace)
-#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
+#if defined(CONFIG_THUMB2_KERNEL) || !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
mov pc, lr
ENDPROC(__backtrace)
ENDPROC(c_backtrace)
@@ -38,7 +38,10 @@ ENDPROC(c_backtrace)
beq no_frame @ we have no stack frames
tst r1, #0x10 @ 26 or 32-bit mode?
- moveq mask, #0xfc000003 @ mask for 26-bit
+ itte eq
+ ARM( moveq mask, #0xfc000003 )
+ THUMB( moveq mask, #0xfc000000 )
+ THUMB( orreq mask, #0x03 )
movne mask, #0 @ mask for 32-bit
1: stmfd sp!, {pc} @ calculate offset of PC stored
@@ -73,6 +76,7 @@ for_each_frame: tst frame, mask @ Check for address exceptions
1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
teq r3, r2, lsr #10 @ instruction
+ ite ne
subne r0, sv_pc, #4 @ allow for mov
subeq r0, sv_pc, #8 @ allow for mov + stmia
@@ -84,6 +88,7 @@ for_each_frame: tst frame, mask @ Check for address exceptions
ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
ldr r3, .Ldsi+4
teq r3, r1, lsr #10
+ ittt eq
ldreq r0, [frame, #-8] @ get sp
subeq r0, r0, #4 @ point at the last arg
bleq .Ldumpstm @ dump saved registers
@@ -91,6 +96,7 @@ for_each_frame: tst frame, mask @ Check for address exceptions
1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
ldr r3, .Ldsi @ instruction exists,
teq r3, r1, lsr #10
+ itt eq
subeq r0, frame, #16
bleq .Ldumpstm @ dump saved registers
@@ -126,10 +132,13 @@ ENDPROC(c_backtrace)
mov reg, #10
mov r7, #0
1: mov r3, #1
- tst instr, r3, lsl reg
+ ARM( tst instr, r3, lsl reg )
+ THUMB( lsl r3, reg )
+ THUMB( tst instr, r3 )
beq 2f
add r7, r7, #1
teq r7, #6
+ itte eq
moveq r7, #1
moveq r1, #'\n'
movne r1, #' '
@@ -140,6 +149,7 @@ ENDPROC(c_backtrace)
2: subs reg, reg, #1
bpl 1b
teq r7, #0
+ itt ne
adrne r0, .Lcr
blne printk
ldmfd sp!, {instr, reg, stack, r7, pc}
diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h
index 2e787d40d599..28c7e4e1ef76 100644
--- a/arch/arm/lib/bitops.h
+++ b/arch/arm/lib/bitops.h
@@ -5,6 +5,13 @@
and r3, r0, #7 @ Get bit offset
add r1, r1, r0, lsr #3 @ Get byte offset
mov r3, r2, lsl r3
+#ifdef CONFIG_ARM_ERRATA_351422
+ mrc p15, 0, r0, c0, c0, 5
+ and r0, r0, #0xf
+ mov r0, r0, lsl #8
+3: subs r0, r0, #1
+ bpl 3b
+#endif
1: ldrexb r2, [r1]
\instr r2, r2, r3
strexb r0, r2, [r1]
@@ -13,18 +20,29 @@
mov pc, lr
.endm
- .macro testop, instr, store
+ .macro testop, instr, store, cond=al
and r3, r0, #7 @ Get bit offset
mov r2, #1
add r1, r1, r0, lsr #3 @ Get byte offset
mov r3, r2, lsl r3 @ create mask
+#ifdef CONFIG_ARM_ERRATA_351422
+ mrc p15, 0, r0, c0, c0, 5
+ and r0, r0, #0xf
+ mov r0, r0, lsl #8
+3: subs r0, r0, #1
+ bpl 3b
+#endif
1: ldrexb r2, [r1]
ands r0, r2, r3 @ save old value of bit
- \instr r2, r2, r3 @ toggle bit
+ .ifnc \cond,al
+ it \cond
+ .endif
+ \instr r2, r2, r3 @ toggle bit
strexb ip, r2, [r1]
cmp ip, #0
bne 1b
cmp r0, #0
+ it ne
movne r0, #1
2: mov pc, lr
.endm
@@ -49,7 +67,7 @@
* Note: we can trivially conditionalise the store instruction
* to avoid dirtying the data cache.
*/
- .macro testop, instr, store
+ .macro testop, instr, store, cond=al
add r1, r1, r0, lsr #3
and r3, r0, #7
mov r0, #1
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S
index 4d6bc71231f3..2147bec77ce4 100644
--- a/arch/arm/lib/clear_user.S
+++ b/arch/arm/lib/clear_user.S
@@ -26,21 +26,20 @@ ENTRY(__clear_user)
ands ip, r0, #3
beq 1f
cmp ip, #2
-USER( strbt r2, [r0], #1)
-USER( strlebt r2, [r0], #1)
-USER( strltbt r2, [r0], #1)
+ strusr r2, r0, 1
+ strusr r2, r0, 1, le
+ strusr r2, r0, 1, lt
rsb ip, ip, #4
sub r1, r1, ip @ 7 6 5 4 3 2 1
1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
-USER( strplt r2, [r0], #4)
-USER( strplt r2, [r0], #4)
+ strusr r2, r0, 4, pl, rept=2
bpl 1b
adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3
-USER( strplt r2, [r0], #4)
+ strusr r2, r0, 4, pl
2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
-USER( strnebt r2, [r0], #1)
-USER( strnebt r2, [r0], #1)
+ strusr r2, r0, 1, ne, rept=2
tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1
+ it ne @ explicit IT needed for the label
USER( strnebt r2, [r0])
mov r0, #0
ldmfd sp!, {r1, pc}
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index 56799a165cc4..9a7a16426428 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -33,11 +33,15 @@
* Number of bytes NOT copied.
*/
+#ifndef CONFIG_THUMB2_KERNEL
+#define LDR1W_SHIFT 0
+#else
+#define LDR1W_SHIFT 1
+#endif
+#define STR1W_SHIFT 0
+
.macro ldr1w ptr reg abort
-100: ldrt \reg, [\ptr], #4
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ ldrusr \reg, \ptr, 4, abort=\abort
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -53,14 +57,11 @@
.endm
.macro ldr1b ptr reg cond=al abort
-100: ldr\cond\()bt \reg, [\ptr], #1
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ ldrusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro str1w ptr reg abort
- str \reg, [\ptr], #4
+ W(str) \reg, [\ptr], #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
@@ -68,6 +69,9 @@
.endm
.macro str1b ptr reg cond=al abort
+ .ifnc \cond,al
+ it \cond
+ .endif
str\cond\()b \reg, [\ptr], #1
.endm
diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
index 6ae04db1ca4f..1c57a034cadf 100644
--- a/arch/arm/lib/copy_page.S
+++ b/arch/arm/lib/copy_page.S
@@ -39,8 +39,10 @@ ENTRY(copy_page)
ldmia r1!, {r3, r4, ip, lr} @ 4
subs r2, r2, #1 @ 1
stmia r0!, {r3, r4, ip, lr} @ 4
+ itt gt
ldmgtia r1!, {r3, r4, ip, lr} @ 4
bgt 1b @ 1
+ PLD( itt eq )
PLD( ldmeqia r1!, {r3, r4, ip, lr} )
PLD( beq 2b )
ldmfd sp!, {r4, pc} @ 3
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S
index 139cce646055..8e8fc03f55bd 100644
--- a/arch/arm/lib/copy_template.S
+++ b/arch/arm/lib/copy_template.S
@@ -57,6 +57,13 @@
*
* Restore registers with the values previously saved with the
* 'preserv' macro. Called upon code termination.
+ *
+ * LDR1W_SHIFT
+ * STR1W_SHIFT
+ *
+ * Correction to be applied to the "ip" register when branching into
+ * the ldr1w or str1w instructions (some of these macros may expand to
+ * than one 32bit instruction in Thumb-2)
*/
@@ -99,9 +106,16 @@
5: ands ip, r2, #28
rsb ip, ip, #32
+#if LDR1W_SHIFT > 0
+ lsl ip, ip, #LDR1W_SHIFT
+#endif
+ it ne
addne pc, pc, ip @ C is always clear here
b 7f
-6: nop
+6:
+ .rept (1 << LDR1W_SHIFT)
+ W(nop)
+ .endr
ldr1w r1, r3, abort=20f
ldr1w r1, r4, abort=20f
ldr1w r1, r5, abort=20f
@@ -110,9 +124,16 @@
ldr1w r1, r8, abort=20f
ldr1w r1, lr, abort=20f
+#if LDR1W_SHIFT < STR1W_SHIFT
+ lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
+#elif LDR1W_SHIFT > STR1W_SHIFT
+ lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
+#endif
add pc, pc, ip
nop
- nop
+ .rept (1 << STR1W_SHIFT)
+ W(nop)
+ .endr
str1w r0, r3, abort=20f
str1w r0, r4, abort=20f
str1w r0, r5, abort=20f
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index 22f968bbdffd..dc0fe7391527 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -33,8 +33,15 @@
* Number of bytes NOT copied.
*/
+#define LDR1W_SHIFT 0
+#ifndef CONFIG_THUMB2_KERNEL
+#define STR1W_SHIFT 0
+#else
+#define STR1W_SHIFT 1
+#endif
+
.macro ldr1w ptr reg abort
- ldr \reg, [\ptr], #4
+ W(ldr) \reg, [\ptr], #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -46,14 +53,14 @@
.endm
.macro ldr1b ptr reg cond=al abort
+ .ifnc \cond,al
+ it \cond
+ .endif
ldr\cond\()b \reg, [\ptr], #1
.endm
.macro str1w ptr reg abort
-100: strt \reg, [\ptr], #4
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ strusr \reg, \ptr, 4, abort=\abort
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
@@ -68,10 +75,7 @@
.endm
.macro str1b ptr reg cond=al abort
-100: str\cond\()bt \reg, [\ptr], #1
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ strusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro enter reg1 reg2
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S
index 31d3cb34740d..e9a504e4302e 100644
--- a/arch/arm/lib/csumpartial.S
+++ b/arch/arm/lib/csumpartial.S
@@ -39,6 +39,7 @@ td3 .req lr
/* we must have at least one byte. */
tst buf, #1 @ odd address?
+ itttt ne
movne sum, sum, ror #8
ldrneb td0, [buf], #1
subne len, len, #1
@@ -68,25 +69,30 @@ td3 .req lr
bne .Lless8_wordlp
.Lless8_byte: tst len, #1 @ odd number of bytes
+ itt ne
ldrneb td0, [buf], #1 @ include last byte
adcnes sum, sum, td0, put_byte_0 @ update checksum
.Ldone: adc r0, sum, #0 @ collect up the last carry
ldr td0, [sp], #4
tst td0, #1 @ check buffer alignment
+ it ne
movne r0, r0, ror #8 @ rotate checksum by 8 bits
ldr pc, [sp], #4 @ return
.Lnot_aligned: tst buf, #1 @ odd address
+ ittt ne
ldrneb td0, [buf], #1 @ make even
subne len, len, #1
adcnes sum, sum, td0, put_byte_1 @ update checksum
tst buf, #2 @ 32-bit aligned?
#if __LINUX_ARM_ARCH__ >= 4
+ itt ne
ldrneh td0, [buf], #2 @ make 32-bit aligned
subne len, len, #2
#else
+ itttt ne
ldrneb td0, [buf], #1
ldrneb ip, [buf], #1
subne len, len, #2
@@ -96,6 +102,7 @@ td3 .req lr
orrne td0, ip, td0, lsl #8
#endif
#endif
+ it ne
adcnes sum, sum, td0 @ update checksum
mov pc, lr
@@ -105,10 +112,12 @@ ENTRY(csum_partial)
blo .Lless8 @ 8 bytes to copy.
tst buf, #1
+ it ne
movne sum, sum, ror #8
adds sum, sum, #0 @ C = 0
tst buf, #3 @ Test destination alignment
+ it ne
blne .Lnot_aligned @ align destination, return here
1: bics ip, len, #31
diff --git a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S
index d620a5f22a09..8e1c141b6524 100644
--- a/arch/arm/lib/csumpartialcopygeneric.S
+++ b/arch/arm/lib/csumpartialcopygeneric.S
@@ -40,6 +40,7 @@ sum .req r3
adcs sum, sum, ip, put_byte_1 @ update checksum
strb ip, [dst], #1
tst dst, #2
+ it eq
moveq pc, lr @ dst is now 32bit aligned
.Ldst_16bit: load2b r8, ip
@@ -94,6 +95,7 @@ FN_ENTRY
adds sum, sum, #0 @ C = 0
tst dst, #3 @ Test destination alignment
+ it ne
blne .Ldst_unaligned @ align destination, return here
/*
@@ -147,6 +149,7 @@ FN_ENTRY
strb r5, [dst], #1
mov r5, r4, get_byte_2
.Lexit: tst len, #1
+ ittt ne
strneb r5, [dst], #1
andne r5, r5, #255
adcnes sum, sum, r5, put_byte_0
@@ -160,6 +163,7 @@ FN_ENTRY
.Ldone: adc r0, sum, #0
ldr sum, [sp, #0] @ dst
tst sum, #1
+ it ne
movne r0, r0, ror #8
load_regs
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S
index 14677fb4b0c4..152ed83480f7 100644
--- a/arch/arm/lib/csumpartialcopyuser.S
+++ b/arch/arm/lib/csumpartialcopyuser.S
@@ -26,50 +26,28 @@
.endm
.macro load1b, reg1
-9999: ldrbt \reg1, [r0], $1
- .section __ex_table, "a"
- .align 3
- .long 9999b, 6001f
- .previous
+ ldrusr \reg1, r0, 1
.endm
.macro load2b, reg1, reg2
-9999: ldrbt \reg1, [r0], $1
-9998: ldrbt \reg2, [r0], $1
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .previous
+ ldrusr \reg1, r0, 1
+ ldrusr \reg2, r0, 1
.endm
.macro load1l, reg1
-9999: ldrt \reg1, [r0], $4
- .section __ex_table, "a"
- .align 3
- .long 9999b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
.endm
.macro load2l, reg1, reg2
-9999: ldrt \reg1, [r0], $4
-9998: ldrt \reg2, [r0], $4
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
+ ldrusr \reg2, r0, 4
.endm
.macro load4l, reg1, reg2, reg3, reg4
-9999: ldrt \reg1, [r0], $4
-9998: ldrt \reg2, [r0], $4
-9997: ldrt \reg3, [r0], $4
-9996: ldrt \reg4, [r0], $4
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .long 9997b, 6001f
- .long 9996b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
+ ldrusr \reg2, r0, 4
+ ldrusr \reg3, r0, 4
+ ldrusr \reg4, r0, 4
.endm
/*
@@ -92,14 +70,15 @@
*/
.section .fixup,"ax"
.align 4
-6001: mov r4, #-EFAULT
+9001: mov r4, #-EFAULT
ldr r5, [fp, #4] @ *err_ptr
str r4, [r5]
ldmia sp, {r1, r2} @ retrieve dst, len
add r2, r2, r1
mov r0, #0 @ zero the buffer
-6002: teq r2, r1
+9002: teq r2, r1
+ it ne
strneb r0, [r1], #1
- bne 6002b
+ bne 9002b
load_regs
.previous
diff --git a/arch/arm/lib/delay.S b/arch/arm/lib/delay.S
index 8d6a8762ab88..fcd87ffe2b1d 100644
--- a/arch/arm/lib/delay.S
+++ b/arch/arm/lib/delay.S
@@ -31,6 +31,7 @@ ENTRY(__const_udelay) @ 0 <= r0 <= 0x7fffff06
mov r2, r2, lsr #10 @ max = 0x00007fff
mul r0, r2, r0 @ max = 2^32-1
movs r0, r0, lsr #6
+ it eq
moveq pc, lr
/*
@@ -58,6 +59,7 @@ ENTRY(__delay)
movls pc, lr
subs r0, r0, #1
#endif
+ it hi
bhi __delay
mov pc, lr
ENDPROC(__udelay)
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index 1425e789ba86..d02268ac7baf 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -84,8 +84,10 @@ ENTRY(__do_div64)
@ The division loop for needed upper bit positions.
@ Break out early if dividend reaches 0.
2: cmp xh, yl
+ itt cs
orrcs yh, yh, ip
subcss xh, xh, yl
+ it ne
movnes ip, ip, lsr #1
mov yl, yl, lsr #1
bne 2b
@@ -93,7 +95,9 @@ ENTRY(__do_div64)
@ See if we need to handle lower 32-bit result.
3: cmp xh, #0
mov yl, #0
+ it eq
cmpeq xl, r4
+ itt lo
movlo xh, xl
movlo pc, lr
@@ -104,7 +108,9 @@ ENTRY(__do_div64)
4: movs xl, xl, lsl #1
adcs xh, xh, xh
beq 6f
+ it cc
cmpcc xh, r4
+ itt cs
5: orrcs yl, yl, ip
subcs xh, xh, r4
movs ip, ip, lsr #1
@@ -116,6 +122,7 @@ ENTRY(__do_div64)
@ Otherwise, if lower part is also null then we are done.
6: bcs 5b
cmp xl, #0
+ it eq
moveq pc, lr
@ We still have remainer bits in the low part. Bring them up.
@@ -177,13 +184,16 @@ ENTRY(__do_div64)
mov yh, xh, lsr ip
mov yl, xl, lsr ip
rsb ip, ip, #32
- orr yl, yl, xh, lsl ip
+ ARM( orr yl, yl, xh, lsl ip )
+ THUMB( lsl xh, xh, ip )
+ THUMB( orr yl, yl, xh )
mov xh, xl, lsl ip
mov xh, xh, lsr ip
mov pc, lr
@ eq -> division by 1: obvious enough...
-9: moveq yl, xl
+9: itttt eq
+ moveq yl, xl
moveq yh, xh
moveq xh, #0
moveq pc, lr
diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S
index 8c4defc4f3c4..1e4cbd4e7be9 100644
--- a/arch/arm/lib/findbit.S
+++ b/arch/arm/lib/findbit.S
@@ -25,7 +25,10 @@ ENTRY(_find_first_zero_bit_le)
teq r1, #0
beq 3f
mov r2, #0
-1: ldrb r3, [r0, r2, lsr #3]
+1:
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eors r3, r3, #0xff @ invert bits
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -44,7 +47,9 @@ ENTRY(_find_next_zero_bit_le)
beq 3b
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
- ldrb r3, [r0, r2, lsr #3]
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eor r3, r3, #0xff @ now looking for a 1 bit
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
@@ -61,7 +66,10 @@ ENTRY(_find_first_bit_le)
teq r1, #0
beq 3f
mov r2, #0
-1: ldrb r3, [r0, r2, lsr #3]
+1:
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -80,7 +88,9 @@ ENTRY(_find_next_bit_le)
beq 3b
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
- ldrb r3, [r0, r2, lsr #3]
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
orr r2, r2, #7 @ if zero, then no bits here
@@ -95,7 +105,9 @@ ENTRY(_find_first_zero_bit_be)
beq 3f
mov r2, #0
1: eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eors r3, r3, #0xff @ invert bits
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -111,7 +123,9 @@ ENTRY(_find_next_zero_bit_be)
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eor r3, r3, #0xff @ now looking for a 1 bit
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
@@ -125,7 +139,9 @@ ENTRY(_find_first_bit_be)
beq 3f
mov r2, #0
1: eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -141,7 +157,9 @@ ENTRY(_find_next_bit_be)
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
orr r2, r2, #7 @ if zero, then no bits here
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 6763088b7607..3e1b98056c50 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -36,7 +36,10 @@ ENTRY(__get_user_1)
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
-2: ldrbt r2, [r0], #1
+2:
+ ARM( ldrbt r2, [r0], #1 )
+ THUMB( ldrbt r2, [r0] )
+ THUMB( add r0, #1 )
3: ldrbt r3, [r0]
#ifndef __ARMEB__
orr r2, r2, r3, lsl #8
diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S
index 9f4238987fe9..45229e46ed5b 100644
--- a/arch/arm/lib/io-readsb.S
+++ b/arch/arm/lib/io-readsb.S
@@ -12,12 +12,15 @@
.Linsb_align: rsb ip, ip, #4
cmp ip, r2
+ it gt
movgt ip, r2
cmp ip, #2
ldrb r3, [r0]
strb r3, [r1], #1
+ itt ge
ldrgeb r3, [r0]
strgeb r3, [r1], #1
+ itt gt
ldrgtb r3, [r0]
strgtb r3, [r1], #1
subs r2, r2, ip
@@ -25,6 +28,7 @@
ENTRY(__raw_readsb)
teq r2, #0 @ do we have to check for the zero len?
+ it eq
moveq pc, lr
ands ip, r1, #3
bne .Linsb_align
@@ -72,6 +76,7 @@ ENTRY(__raw_readsb)
bpl .Linsb_16_lp
tst r2, #15
+ it eq
ldmeqfd sp!, {r4 - r6, pc}
.Linsb_no_16: tst r2, #8
@@ -109,13 +114,16 @@ ENTRY(__raw_readsb)
str r3, [r1], #4
.Linsb_no_4: ands r2, r2, #3
+ it eq
ldmeqfd sp!, {r4 - r6, pc}
cmp r2, #2
ldrb r3, [r0]
strb r3, [r1], #1
+ itt ge
ldrgeb r3, [r0]
strgeb r3, [r1], #1
+ itt gt
ldrgtb r3, [r0]
strgtb r3, [r1]
diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S
index 5fb97e7f9f4b..1f02e66d079c 100644
--- a/arch/arm/lib/io-readsl.S
+++ b/arch/arm/lib/io-readsl.S
@@ -12,6 +12,7 @@
ENTRY(__raw_readsl)
teq r2, #0 @ do we have to check for the zero len?
+ it eq
moveq pc, lr
ands ip, r1, #3
bne 3f
@@ -28,9 +29,11 @@ ENTRY(__raw_readsl)
bpl 1b
ldmfd sp!, {r4, lr}
2: movs r2, r2, lsl #31
+ ittt cs
ldrcs r3, [r0, #0]
ldrcs ip, [r0, #0]
stmcsia r1!, {r3, ip}
+ itt ne
ldrne r3, [r0, #0]
strne r3, [r1, #0]
mov pc, lr
@@ -48,6 +51,7 @@ ENTRY(__raw_readsl)
4: subs r2, r2, #1
mov ip, r3, pull #24
+ itttt ne
ldrne r3, [r0]
orrne ip, ip, r3, push #8
strne ip, [r1], #4
@@ -56,6 +60,7 @@ ENTRY(__raw_readsl)
5: subs r2, r2, #1
mov ip, r3, pull #16
+ itttt ne
ldrne r3, [r0]
orrne ip, ip, r3, push #16
strne ip, [r1], #4
@@ -64,6 +69,7 @@ ENTRY(__raw_readsl)
6: subs r2, r2, #1
mov ip, r3, pull #8
+ itttt ne
ldrne r3, [r0]
orrne ip, ip, r3, push #24
strne ip, [r1], #4
diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S
index 1f393d42593d..9db32f0541da 100644
--- a/arch/arm/lib/io-readsw-armv4.S
+++ b/arch/arm/lib/io-readsw-armv4.S
@@ -26,6 +26,7 @@
ENTRY(__raw_readsw)
teq r2, #0
+ it eq
moveq pc, lr
tst r1, #3
bne .Linsw_align
@@ -76,7 +77,8 @@ ENTRY(__raw_readsw)
pack r3, r3, ip
str r3, [r1], #4
-.Lno_insw_2: ldrneh r3, [r0]
+.Lno_insw_2: itt ne
+ ldrneh r3, [r0]
strneh r3, [r1]
ldmfd sp!, {r4, r5, pc}
@@ -94,6 +96,7 @@ ENTRY(__raw_readsw)
#endif
.Linsw_noalign: stmfd sp!, {r4, lr}
+ it cc
ldrccb ip, [r1, #-1]!
bcc 1f
@@ -121,6 +124,7 @@ ENTRY(__raw_readsw)
3: tst r2, #1
strb ip, [r1], #1
+ itttt ne
ldrneh ip, [r0]
_BE_ONLY_( movne ip, ip, ror #8 )
strneb ip, [r1], #1
diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S
index 68b92f4acaeb..5fad6b0c7f05 100644
--- a/arch/arm/lib/io-writesb.S
+++ b/arch/arm/lib/io-writesb.S
@@ -32,12 +32,15 @@
.Loutsb_align: rsb ip, ip, #4
cmp ip, r2
+ it gt
movgt ip, r2
cmp ip, #2
ldrb r3, [r1], #1
strb r3, [r0]
+ itt ge
ldrgeb r3, [r1], #1
strgeb r3, [r0]
+ itt gt
ldrgtb r3, [r1], #1
strgtb r3, [r0]
subs r2, r2, ip
@@ -45,6 +48,7 @@
ENTRY(__raw_writesb)
teq r2, #0 @ do we have to check for the zero len?
+ it eq
moveq pc, lr
ands ip, r1, #3
bne .Loutsb_align
@@ -64,6 +68,7 @@ ENTRY(__raw_writesb)
bpl .Loutsb_16_lp
tst r2, #15
+ it eq
ldmeqfd sp!, {r4, r5, pc}
.Loutsb_no_16: tst r2, #8
@@ -80,13 +85,16 @@ ENTRY(__raw_writesb)
outword r3
.Loutsb_no_4: ands r2, r2, #3
+ it eq
ldmeqfd sp!, {r4, r5, pc}
cmp r2, #2
ldrb r3, [r1], #1
strb r3, [r0]
+ itt ge
ldrgeb r3, [r1], #1
strgeb r3, [r0]
+ itt gt
ldrgtb r3, [r1]
strgtb r3, [r0]
diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S
index 8d3b7813725c..ced1d9169090 100644
--- a/arch/arm/lib/io-writesl.S
+++ b/arch/arm/lib/io-writesl.S
@@ -12,6 +12,7 @@
ENTRY(__raw_writesl)
teq r2, #0 @ do we have to check for the zero len?
+ it eq
moveq pc, lr
ands ip, r1, #3
bne 3f
@@ -28,10 +29,14 @@ ENTRY(__raw_writesl)
bpl 1b
ldmfd sp!, {r4, lr}
2: movs r2, r2, lsl #31
+ itt cs
ldmcsia r1!, {r3, ip}
strcs r3, [r0, #0]
+ it ne
ldrne r3, [r1, #0]
+ it cs
strcs ip, [r0, #0]
+ it ne
strne r3, [r0, #0]
mov pc, lr
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S
index d6585612c86b..bb8530310ff3 100644
--- a/arch/arm/lib/io-writesw-armv4.S
+++ b/arch/arm/lib/io-writesw-armv4.S
@@ -31,6 +31,7 @@
ENTRY(__raw_writesw)
teq r2, #0
+ it eq
moveq pc, lr
ands r3, r1, #3
bne .Loutsw_align
@@ -61,7 +62,8 @@ ENTRY(__raw_writesw)
ldr r3, [r1], #4
outword r3
-.Lno_outsw_2: ldrneh r3, [r1]
+.Lno_outsw_2: itt ne
+ ldrneh r3, [r1]
strneh r3, [r0]
ldmfd sp!, {r4, r5, pc}
@@ -75,7 +77,11 @@ ENTRY(__raw_writesw)
#endif
.Loutsw_noalign:
- ldr r3, [r1, -r3]!
+ ARM( ldr r3, [r1, -r3]! )
+ THUMB( rsb r3, r3, #0 )
+ THUMB( ldr r3, [r1, r3] )
+ THUMB( sub r1, r3 )
+ it cs
subcs r2, r2, #1
bcs 2f
subs r2, r2, #2
@@ -91,7 +97,8 @@ ENTRY(__raw_writesw)
bpl 1b
tst r2, #1
-3: movne ip, r3, lsr #8
+3: itt ne
+ movne ip, r3, lsr #8
strneh ip, [r0]
mov pc, lr
ENDPROC(__raw_writesw)
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index 67964bcfc854..1eb73e769c6c 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -56,6 +56,7 @@ Boston, MA 02111-1307, USA. */
@ at the left end of each 4 bit nibbles in the division loop
@ to save one loop in most cases.
tst \divisor, #0xe0000000
+ itte eq
moveq \divisor, \divisor, lsl #3
moveq \curbit, #8
movne \curbit, #1
@@ -65,6 +66,7 @@ Boston, MA 02111-1307, USA. */
@ division loop. Continue shifting until the divisor is
@ larger than the dividend.
1: cmp \divisor, #0x10000000
+ ittt lo
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #4
movlo \curbit, \curbit, lsl #4
@@ -73,6 +75,7 @@ Boston, MA 02111-1307, USA. */
@ For very big divisors, we must shift it a bit at a time, or
@ we will be in danger of overflowing.
1: cmp \divisor, #0x80000000
+ ittt lo
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #1
movlo \curbit, \curbit, lsl #1
@@ -84,19 +87,25 @@ Boston, MA 02111-1307, USA. */
@ Division loop
1: cmp \dividend, \divisor
+ itt hs
subhs \dividend, \dividend, \divisor
orrhs \result, \result, \curbit
cmp \dividend, \divisor, lsr #1
+ itt hs
subhs \dividend, \dividend, \divisor, lsr #1
orrhs \result, \result, \curbit, lsr #1
cmp \dividend, \divisor, lsr #2
+ itt hs
subhs \dividend, \dividend, \divisor, lsr #2
orrhs \result, \result, \curbit, lsr #2
cmp \dividend, \divisor, lsr #3
+ itt hs
subhs \dividend, \dividend, \divisor, lsr #3
orrhs \result, \result, \curbit, lsr #3
cmp \dividend, #0 @ Early termination?
+ it ne
movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
+ it ne
movne \divisor, \divisor, lsr #4
bne 1b
@@ -113,19 +122,24 @@ Boston, MA 02111-1307, USA. */
#else
cmp \divisor, #(1 << 16)
+ itt hs
movhs \divisor, \divisor, lsr #16
movhs \order, #16
+ it lo
movlo \order, #0
cmp \divisor, #(1 << 8)
+ itt hs
movhs \divisor, \divisor, lsr #8
addhs \order, \order, #8
cmp \divisor, #(1 << 4)
+ itt hs
movhs \divisor, \divisor, lsr #4
addhs \order, \order, #4
cmp \divisor, #(1 << 2)
+ ite hi
addhi \order, \order, #3
addls \order, \order, \divisor, lsr #1
@@ -152,6 +166,7 @@ Boston, MA 02111-1307, USA. */
@ division loop. Continue shifting until the divisor is
@ larger than the dividend.
1: cmp \divisor, #0x10000000
+ ittt lo
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #4
addlo \order, \order, #4
@@ -160,6 +175,7 @@ Boston, MA 02111-1307, USA. */
@ For very big divisors, we must shift it a bit at a time, or
@ we will be in danger of overflowing.
1: cmp \divisor, #0x80000000
+ ittt lo
cmplo \divisor, \dividend
movlo \divisor, \divisor, lsl #1
addlo \order, \order, #1
@@ -173,19 +189,25 @@ Boston, MA 02111-1307, USA. */
blt 2f
1: cmp \dividend, \divisor
+ it hs
subhs \dividend, \dividend, \divisor
cmp \dividend, \divisor, lsr #1
+ it hs
subhs \dividend, \dividend, \divisor, lsr #1
cmp \dividend, \divisor, lsr #2
+ it hs
subhs \dividend, \dividend, \divisor, lsr #2
cmp \dividend, \divisor, lsr #3
+ it hs
subhs \dividend, \dividend, \divisor, lsr #3
cmp \dividend, #1
mov \divisor, \divisor, lsr #4
+ it ge
subges \order, \order, #4
bge 1b
tst \order, #3
+ it ne
teqne \dividend, #0
beq 5f
@@ -194,12 +216,15 @@ Boston, MA 02111-1307, USA. */
blt 4f
beq 3f
cmp \dividend, \divisor
+ it hs
subhs \dividend, \dividend, \divisor
mov \divisor, \divisor, lsr #1
3: cmp \dividend, \divisor
+ it hs
subhs \dividend, \dividend, \divisor
mov \divisor, \divisor, lsr #1
4: cmp \dividend, \divisor
+ it hs
subhs \dividend, \dividend, \divisor
5:
.endm
@@ -209,6 +234,7 @@ ENTRY(__udivsi3)
ENTRY(__aeabi_uidiv)
subs r2, r1, #1
+ it eq
moveq pc, lr
bcc Ldiv0
cmp r0, r1
@@ -221,7 +247,8 @@ ENTRY(__aeabi_uidiv)
mov r0, r2
mov pc, lr
-11: moveq r0, #1
+11: ite eq
+ moveq r0, #1
movne r0, #0
mov pc, lr
@@ -237,10 +264,14 @@ ENTRY(__umodsi3)
subs r2, r1, #1 @ compare divisor with 1
bcc Ldiv0
+ ite ne
cmpne r0, r1 @ compare dividend with divisor
moveq r0, #0
+ it hi
tsthi r1, r2 @ see if divisor is power of 2
+ it eq
andeq r0, r0, r2
+ it ls
movls pc, lr
ARM_MOD_BODY r0, r1, r2, r3
@@ -255,10 +286,12 @@ ENTRY(__aeabi_idiv)
cmp r1, #0
eor ip, r0, r1 @ save the sign of the result.
beq Ldiv0
+ it mi
rsbmi r1, r1, #0 @ loops below use unsigned.
subs r2, r1, #1 @ division by 1 or -1 ?
beq 10f
movs r3, r0
+ it mi
rsbmi r3, r0, #0 @ positive dividend value
cmp r3, r1
bls 11f
@@ -268,14 +301,18 @@ ENTRY(__aeabi_idiv)
ARM_DIV_BODY r3, r1, r0, r2
cmp ip, #0
+ it mi
rsbmi r0, r0, #0
mov pc, lr
10: teq ip, r0 @ same sign ?
+ it mi
rsbmi r0, r0, #0
mov pc, lr
-11: movlo r0, #0
+11: it lo
+ movlo r0, #0
+ itt eq
moveq r0, ip, asr #31
orreq r0, r0, #1
mov pc, lr
@@ -284,6 +321,7 @@ ENTRY(__aeabi_idiv)
cmp ip, #0
mov r0, r3, lsr r2
+ it mi
rsbmi r0, r0, #0
mov pc, lr
@@ -294,19 +332,25 @@ ENTRY(__modsi3)
cmp r1, #0
beq Ldiv0
+ it mi
rsbmi r1, r1, #0 @ loops below use unsigned.
movs ip, r0 @ preserve sign of dividend
+ it mi
rsbmi r0, r0, #0 @ if negative make positive
subs r2, r1, #1 @ compare divisor with 1
+ ite ne
cmpne r0, r1 @ compare dividend with divisor
moveq r0, #0
+ it hi
tsthi r1, r2 @ see if divisor is power of 2
+ it eq
andeq r0, r0, r2
bls 10f
ARM_MOD_BODY r0, r1, r2, r3
10: cmp ip, #0
+ it mi
rsbmi r0, r0, #0
mov pc, lr
diff --git a/arch/arm/lib/lshrdi3.S b/arch/arm/lib/lshrdi3.S
index 99ea338bf87c..57db3a265e5b 100644
--- a/arch/arm/lib/lshrdi3.S
+++ b/arch/arm/lib/lshrdi3.S
@@ -41,9 +41,12 @@ ENTRY(__aeabi_llsr)
subs r3, r2, #32
rsb ip, r2, #32
+ itett mi
movmi al, al, lsr r2
movpl al, ah, lsr r3
- orrmi al, al, ah, lsl ip
+ ARM( orrmi al, al, ah, lsl ip )
+ THUMB( lslmi r3, ah, ip )
+ THUMB( orrmi al, al, r3 )
mov ah, ah, lsr r2
mov pc, lr
diff --git a/arch/arm/lib/memchr.S b/arch/arm/lib/memchr.S
index 1da86991d700..0d1d596ad8cd 100644
--- a/arch/arm/lib/memchr.S
+++ b/arch/arm/lib/memchr.S
@@ -21,6 +21,7 @@ ENTRY(memchr)
teq r3, r1
bne 1b
sub r0, r0, #1
-2: movne r0, #0
+2: it ne
+ movne r0, #0
mov pc, lr
ENDPROC(memchr)
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
index e0d002641d3f..c7a810dee294 100644
--- a/arch/arm/lib/memcpy.S
+++ b/arch/arm/lib/memcpy.S
@@ -13,8 +13,11 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#define LDR1W_SHIFT 0
+#define STR1W_SHIFT 0
+
.macro ldr1w ptr reg abort
- ldr \reg, [\ptr], #4
+ W(ldr) \reg, [\ptr], #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -26,11 +29,16 @@
.endm
.macro ldr1b ptr reg cond=al abort
+ .ifnc \cond,al
+ it \cond
ldr\cond\()b \reg, [\ptr], #1
+ .else
+ ldrb \reg, [\ptr], #1
+ .endif
.endm
.macro str1w ptr reg abort
- str \reg, [\ptr], #4
+ W(str) \reg, [\ptr], #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
@@ -38,7 +46,12 @@
.endm
.macro str1b ptr reg cond=al abort
+ .ifnc \cond,al
+ it \cond
str\cond\()b \reg, [\ptr], #1
+ .else
+ strb \reg, [\ptr], #1
+ .endif
.endm
.macro enter reg1 reg2
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S
index 12549187088c..191a5dc41596 100644
--- a/arch/arm/lib/memmove.S
+++ b/arch/arm/lib/memmove.S
@@ -29,7 +29,9 @@
ENTRY(memmove)
subs ip, r0, r1
+ it hi
cmphi r2, ip
+ it ls
bls memcpy
stmfd sp!, {r0, r4, lr}
@@ -72,46 +74,55 @@ ENTRY(memmove)
5: ands ip, r2, #28
rsb ip, ip, #32
+ it ne
addne pc, pc, ip @ C is always clear here
b 7f
6: nop
- ldr r3, [r1, #-4]!
- ldr r4, [r1, #-4]!
- ldr r5, [r1, #-4]!
- ldr r6, [r1, #-4]!
- ldr r7, [r1, #-4]!
- ldr r8, [r1, #-4]!
- ldr lr, [r1, #-4]!
+ W(ldr) r3, [r1, #-4]!
+ W(ldr) r4, [r1, #-4]!
+ W(ldr) r5, [r1, #-4]!
+ W(ldr) r6, [r1, #-4]!
+ W(ldr) r7, [r1, #-4]!
+ W(ldr) r8, [r1, #-4]!
+ W(ldr) lr, [r1, #-4]!
add pc, pc, ip
nop
nop
- str r3, [r0, #-4]!
- str r4, [r0, #-4]!
- str r5, [r0, #-4]!
- str r6, [r0, #-4]!
- str r7, [r0, #-4]!
- str r8, [r0, #-4]!
- str lr, [r0, #-4]!
+ W(str) r3, [r0, #-4]!
+ W(str) r4, [r0, #-4]!
+ W(str) r5, [r0, #-4]!
+ W(str) r6, [r0, #-4]!
+ W(str) r7, [r0, #-4]!
+ W(str) r8, [r0, #-4]!
+ W(str) lr, [r0, #-4]!
CALGN( bcs 2b )
7: ldmfd sp!, {r5 - r8}
8: movs r2, r2, lsl #31
+ it ne
ldrneb r3, [r1, #-1]!
+ itt cs
ldrcsb r4, [r1, #-1]!
ldrcsb ip, [r1, #-1]
+ it ne
strneb r3, [r0, #-1]!
+ itt cs
strcsb r4, [r0, #-1]!
strcsb ip, [r0, #-1]
ldmfd sp!, {r0, r4, pc}
9: cmp ip, #2
+ it gt
ldrgtb r3, [r1, #-1]!
+ it ge
ldrgeb r4, [r1, #-1]!
ldrb lr, [r1, #-1]!
+ it gt
strgtb r3, [r0, #-1]!
+ it ge
strgeb r4, [r0, #-1]!
subs r2, r2, ip
strb lr, [r0, #-1]!
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 650d5923ab83..5e1253d4df5c 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -19,7 +19,9 @@
1: subs r2, r2, #4 @ 1 do we have enough
blt 5f @ 1 bytes to align with?
cmp r3, #2 @ 1
+ it lt
strltb r1, [r0], #1 @ 1
+ it le
strleb r1, [r0], #1 @ 1
strb r1, [r0], #1 @ 1
add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
@@ -51,19 +53,23 @@ ENTRY(memset)
mov lr, r1
2: subs r2, r2, #64
+ itttt ge
stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
stmgeia r0!, {r1, r3, ip, lr}
stmgeia r0!, {r1, r3, ip, lr}
stmgeia r0!, {r1, r3, ip, lr}
bgt 2b
+ it eq
ldmeqfd sp!, {pc} @ Now <64 bytes to go.
/*
* No need to correct the count; we're only testing bits from now on
*/
tst r2, #32
+ itt ne
stmneia r0!, {r1, r3, ip, lr}
stmneia r0!, {r1, r3, ip, lr}
tst r2, #16
+ it ne
stmneia r0!, {r1, r3, ip, lr}
ldr lr, [sp], #4
@@ -111,17 +117,21 @@ ENTRY(memset)
#endif
4: tst r2, #8
+ it ne
stmneia r0!, {r1, r3}
tst r2, #4
+ it ne
strne r1, [r0], #4
/*
* When we get here, we've got less than 4 bytes to zero. We
* may have an unaligned pointer as well.
*/
5: tst r2, #2
+ itt ne
strneb r1, [r0], #1
strneb r1, [r0], #1
tst r2, #1
+ it ne
strneb r1, [r0], #1
mov pc, lr
ENDPROC(memset)
diff --git a/arch/arm/lib/memzero.S b/arch/arm/lib/memzero.S
index 3fbdef5f802a..a0e319a4c03f 100644
--- a/arch/arm/lib/memzero.S
+++ b/arch/arm/lib/memzero.S
@@ -21,7 +21,9 @@
1: subs r1, r1, #4 @ 1 do we have enough
blt 5f @ 1 bytes to align with?
cmp r3, #2 @ 1
+ it lt
strltb r2, [r0], #1 @ 1
+ it le
strleb r2, [r0], #1 @ 1
strb r2, [r0], #1 @ 1
add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3))
@@ -51,19 +53,23 @@ ENTRY(__memzero)
mov lr, r2 @ 1
3: subs r1, r1, #64 @ 1 write 32 bytes out per loop
+ itttt ge
stmgeia r0!, {r2, r3, ip, lr} @ 4
stmgeia r0!, {r2, r3, ip, lr} @ 4
stmgeia r0!, {r2, r3, ip, lr} @ 4
stmgeia r0!, {r2, r3, ip, lr} @ 4
bgt 3b @ 1
+ it eq
ldmeqfd sp!, {pc} @ 1/2 quick exit
/*
* No need to correct the count; we're only testing bits from now on
*/
tst r1, #32 @ 1
+ itt ne
stmneia r0!, {r2, r3, ip, lr} @ 4
stmneia r0!, {r2, r3, ip, lr} @ 4
tst r1, #16 @ 1 16 bytes or more?
+ it ne
stmneia r0!, {r2, r3, ip, lr} @ 4
ldr lr, [sp], #4 @ 1
@@ -109,17 +115,21 @@ ENTRY(__memzero)
#endif
4: tst r1, #8 @ 1 8 bytes or more?
+ it ne
stmneia r0!, {r2, r3} @ 2
tst r1, #4 @ 1 4 bytes or more?
+ it ne
strne r2, [r0], #4 @ 1
/*
* When we get here, we've got less than 4 bytes to zero. We
* may have an unaligned pointer as well.
*/
5: tst r1, #2 @ 1 2 bytes or more?
+ itt ne
strneb r2, [r0], #1 @ 1
strneb r2, [r0], #1 @ 1
tst r1, #1 @ 1 a byte left over
+ it ne
strneb r2, [r0], #1 @ 1
mov pc, lr @ 1
ENDPROC(__memzero)
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 864f3c1c4f18..4d9dc1a526ee 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -38,10 +38,16 @@ ENDPROC(__put_user_1)
ENTRY(__put_user_2)
mov ip, r2, lsr #8
#ifndef __ARMEB__
-2: strbt r2, [r0], #1
+2:
+ ARM( strbt r2, [r0], #1 )
+ THUMB( strbt r2, [r0] )
+ THUMB( add r0, #1 )
3: strbt ip, [r0]
#else
-2: strbt ip, [r0], #1
+2:
+ ARM( strbt ip, [r0], #1 )
+ THUMB( strbt ip, [r0] )
+ THUMB( add r0, #1 )
3: strbt r2, [r0]
#endif
mov r0, #0
@@ -55,7 +61,10 @@ ENTRY(__put_user_4)
ENDPROC(__put_user_4)
ENTRY(__put_user_8)
-5: strt r2, [r0], #4
+5:
+ ARM( strt r2, [r0], #4 )
+ THUMB( strt r2, [r0] )
+ THUMB( add r0, #4 )
6: strt r3, [r0]
mov r0, #0
mov pc, lr
diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S
index a16fb208c841..09b548cac1a4 100644
--- a/arch/arm/lib/sha1.S
+++ b/arch/arm/lib/sha1.S
@@ -187,6 +187,7 @@ ENTRY(sha_transform)
ENDPROC(sha_transform)
+ .align 2
.L_sha_K:
.word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
@@ -195,6 +196,7 @@ ENDPROC(sha_transform)
* void sha_init(__u32 *buf)
*/
+ .align 2
.L_sha_initial_digest:
.word 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
diff --git a/arch/arm/lib/strchr.S b/arch/arm/lib/strchr.S
index d8f2a1c1aea4..fd4014e54e37 100644
--- a/arch/arm/lib/strchr.S
+++ b/arch/arm/lib/strchr.S
@@ -18,9 +18,11 @@ ENTRY(strchr)
and r1, r1, #0xff
1: ldrb r2, [r0], #1
teq r2, r1
+ it ne
teqne r2, #0
bne 1b
teq r2, r1
+ ite ne
movne r0, #0
subeq r0, r0, #1
mov pc, lr
diff --git a/arch/arm/lib/strncpy_from_user.S b/arch/arm/lib/strncpy_from_user.S
index 330373c26dd9..1c9814f346c6 100644
--- a/arch/arm/lib/strncpy_from_user.S
+++ b/arch/arm/lib/strncpy_from_user.S
@@ -23,7 +23,7 @@
ENTRY(__strncpy_from_user)
mov ip, r1
1: subs r2, r2, #1
-USER( ldrplbt r3, [r1], #1)
+ ldrusr r3, r1, 1, pl
bmi 2f
strb r3, [r0], #1
teq r3, #0
diff --git a/arch/arm/lib/strnlen_user.S b/arch/arm/lib/strnlen_user.S
index 90bb9d020836..7855b2906659 100644
--- a/arch/arm/lib/strnlen_user.S
+++ b/arch/arm/lib/strnlen_user.S
@@ -23,7 +23,7 @@
ENTRY(__strnlen_user)
mov r2, r0
1:
-USER( ldrbt r3, [r0], #1)
+ ldrusr r3, r0, 1
teq r3, #0
beq 2f
subs r1, r1, #1
diff --git a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S
index 302f20cd2423..d7a9440de6b8 100644
--- a/arch/arm/lib/strrchr.S
+++ b/arch/arm/lib/strrchr.S
@@ -18,6 +18,7 @@ ENTRY(strrchr)
mov r3, #0
1: ldrb r2, [r0], #1
teq r2, r1
+ it eq
subeq r3, r0, #1
teq r2, #0
bne 1b
diff --git a/arch/arm/lib/testclearbit.S b/arch/arm/lib/testclearbit.S
index 543d7094d18e..df66c76e8b29 100644
--- a/arch/arm/lib/testclearbit.S
+++ b/arch/arm/lib/testclearbit.S
@@ -15,6 +15,6 @@
ENTRY(_test_and_clear_bit_be)
eor r0, r0, #0x18 @ big endian byte ordering
ENTRY(_test_and_clear_bit_le)
- testop bicne, strneb
+ testop bicne, strneb, ne
ENDPROC(_test_and_clear_bit_be)
ENDPROC(_test_and_clear_bit_le)
diff --git a/arch/arm/lib/testsetbit.S b/arch/arm/lib/testsetbit.S
index 0b3f390401ce..3938bdf446a6 100644
--- a/arch/arm/lib/testsetbit.S
+++ b/arch/arm/lib/testsetbit.S
@@ -15,6 +15,6 @@
ENTRY(_test_and_set_bit_be)
eor r0, r0, #0x18 @ big endian byte ordering
ENTRY(_test_and_set_bit_le)
- testop orreq, streqb
+ testop orreq, streqb, eq
ENDPROC(_test_and_set_bit_be)
ENDPROC(_test_and_set_bit_le)
diff --git a/arch/arm/lib/ucmpdi2.S b/arch/arm/lib/ucmpdi2.S
index f0df6a91db04..503288955242 100644
--- a/arch/arm/lib/ucmpdi2.S
+++ b/arch/arm/lib/ucmpdi2.S
@@ -27,9 +27,13 @@
ENTRY(__ucmpdi2)
cmp xh, yh
+ it eq
cmpeq xl, yl
+ it lo
movlo r0, #0
+ it eq
moveq r0, #1
+ it hi
movhi r0, #2
mov pc, lr
@@ -40,9 +44,13 @@ ENDPROC(__ucmpdi2)
ENTRY(__aeabi_ulcmp)
cmp xh, yh
+ it eq
cmpeq xl, yl
+ it lo
movlo r0, #-1
+ it eq
moveq r0, #0
+ it hi
movhi r0, #1
mov pc, lr
diff --git a/arch/arm/mach-integrator/include/mach/debug-macro.S b/arch/arm/mach-integrator/include/mach/debug-macro.S
index d347d659ea30..ffb7d8961f5e 100644
--- a/arch/arm/mach-integrator/include/mach/debug-macro.S
+++ b/arch/arm/mach-integrator/include/mach/debug-macro.S
@@ -14,6 +14,7 @@
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
+ itee eq
moveq \rx, #0x16000000 @ physical base address
movne \rx, #0xf0000000 @ virtual base
addne \rx, \rx, #0x16000000 >> 4
diff --git a/arch/arm/mach-integrator/include/mach/entry-macro.S b/arch/arm/mach-integrator/include/mach/entry-macro.S
index 7649c57acb53..ce478b5bfb90 100644
--- a/arch/arm/mach-integrator/include/mach/entry-macro.S
+++ b/arch/arm/mach-integrator/include/mach/entry-macro.S
@@ -26,6 +26,7 @@
ldr \irqstat, [\base, #IRQ_STATUS] @ get masked status
ldr \base, =IO_ADDRESS(INTEGRATOR_HDR_BASE)
teq \irqstat, #0
+ itt eq
ldreq \irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
moveq \irqnr, #IRQ_CIC_START
diff --git a/arch/arm/mach-integrator/include/mach/hardware.h b/arch/arm/mach-integrator/include/mach/hardware.h
index 1251319ef9ae..d795642fad22 100644
--- a/arch/arm/mach-integrator/include/mach/hardware.h
+++ b/arch/arm/mach-integrator/include/mach/hardware.h
@@ -36,8 +36,12 @@
#define PCIO_BASE PCI_IO_VADDR
#define PCIMEM_BASE PCI_MEMORY_VADDR
+#ifdef CONFIG_MMU
/* macro to get at IO space when running virtually */
#define IO_ADDRESS(x) (((x) >> 4) + IO_BASE)
+#else
+#define IO_ADDRESS(x) (x)
+#endif
#define pcibios_assign_all_busses() 1
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 4ac04055c2ea..452931b2690e 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -49,14 +49,14 @@
#define INTCP_PA_CLCD_BASE 0xc0000000
-#define INTCP_VA_CIC_BASE 0xf1000040
-#define INTCP_VA_PIC_BASE 0xf1400000
-#define INTCP_VA_SIC_BASE 0xfca00000
+#define INTCP_VA_CIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + 0x40
+#define INTCP_VA_PIC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE)
+#define INTCP_VA_SIC_BASE IO_ADDRESS(0xca000000)
#define INTCP_PA_ETH_BASE 0xc8000000
#define INTCP_ETH_SIZE 0x10
-#define INTCP_VA_CTRL_BASE 0xfcb00000
+#define INTCP_VA_CTRL_BASE IO_ADDRESS(0xcb000000)
#define INTCP_FLASHPROG 0x04
#define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0)
#define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1)
@@ -121,12 +121,12 @@ static struct map_desc intcp_io_desc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = 0xfca00000,
+ .virtual = IO_ADDRESS(0xca000000),
.pfn = __phys_to_pfn(0xca000000),
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = 0xfcb00000,
+ .virtual = IO_ADDRESS(0xcb000000),
.pfn = __phys_to_pfn(0xcb000000),
.length = SZ_4K,
.type = MT_DEVICE
@@ -394,8 +394,8 @@ static struct platform_device *intcp_devs[] __initdata = {
*/
static unsigned int mmc_status(struct device *dev)
{
- unsigned int status = readl(0xfca00004);
- writel(8, 0xfcb00008);
+ unsigned int status = readl(IO_ADDRESS(0xca000000) + 4);
+ writel(8, IO_ADDRESS(0xcb000000) + 8);
return status & 8;
}
diff --git a/arch/arm/mach-mps/Kconfig b/arch/arm/mach-mps/Kconfig
new file mode 100644
index 000000000000..b5c1651eec37
--- /dev/null
+++ b/arch/arm/mach-mps/Kconfig
@@ -0,0 +1,11 @@
+if ARCH_MPS
+
+config MACH_MPS
+ bool
+ default y
+ select ARM_NVIC if CPU_V7M
+ help
+ Include support for the ARM Ltd. Microcontroller Prototyping
+ System platform.
+
+endif
diff --git a/arch/arm/mach-mps/Makefile b/arch/arm/mach-mps/Makefile
new file mode 100644
index 000000000000..38bde634fc84
--- /dev/null
+++ b/arch/arm/mach-mps/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := core.o clock.o
+obj-$(CONFIG_MACH_MPS) += board-mps.o
diff --git a/arch/arm/mach-mps/Makefile.boot b/arch/arm/mach-mps/Makefile.boot
new file mode 100644
index 000000000000..8842bf950bdd
--- /dev/null
+++ b/arch/arm/mach-mps/Makefile.boot
@@ -0,0 +1,3 @@
+ zreladdr-y := 0x10008000
+params_phys-y := 0x10000100
+initrd_phys-y := 0x10800000
diff --git a/arch/arm/mach-mps/board-mps.c b/arch/arm/mach-mps/board-mps.c
new file mode 100644
index 000000000000..03c1544893a5
--- /dev/null
+++ b/arch/arm/mach-mps/board-mps.c
@@ -0,0 +1,191 @@
+/*
+ * linux/arch/arm/mach-mps/board_mps.c
+ *
+ * Copyright (C) 2009 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/amba/bus.h>
+
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/nvic.h>
+#include <asm/hardware/icst307.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
+
+#include <mach/platform.h>
+#include <mach/irqs.h>
+
+#include "core.h"
+#include "clock.h"
+
+#if PAGE_OFFSET != PHYS_OFFSET
+#error "PAGE_OFFSET != PHYS_OFFSET"
+#endif
+
+static void __init mps_map_io(void)
+{
+}
+
+/*
+ * MPS AMBA devices
+ */
+
+#define GPIO2_IRQ { IRQ_MPS_GPIO2, NO_IRQ }
+#define GPIO3_IRQ { IRQ_MPS_GPIO3, NO_IRQ }
+
+#define AACI_IRQ { IRQ_MPS_AACI, NO_IRQ }
+#define MMCI_IRQ { IRQ_MPS_MMCIA, IRQ_MPS_MMCIB }
+
+#define SMC_IRQ { NO_IRQ, NO_IRQ }
+#define MPMC_IRQ { NO_IRQ, NO_IRQ }
+#define CLCD_IRQ { IRQ_MPS_CLCD, NO_IRQ }
+
+#define SCTL_IRQ { NO_IRQ, NO_IRQ }
+#define WATCHDOG_IRQ { IRQ_MPS_WDOG, NO_IRQ }
+#define GPIO0_IRQ { IRQ_MPS_GPIO0, NO_IRQ }
+#define GPIO1_IRQ { IRQ_MPS_GPIO1, NO_IRQ }
+#define RTC_IRQ { IRQ_MPS_RTC, NO_IRQ }
+
+#define UART0_IRQ { IRQ_MPS_UART0, NO_IRQ }
+#define UART1_IRQ { IRQ_MPS_UART1, NO_IRQ }
+#define UART2_IRQ { IRQ_MPS_UART2, NO_IRQ }
+#define UART3_IRQ { IRQ_MPS_UART3, NO_IRQ }
+#define SPI_IRQ { IRQ_MPS_SPI, NO_IRQ }
+
+/* FPGA Primecells */
+AMBA_DEVICE(aaci, "fpga:04", AACI, NULL);
+AMBA_DEVICE(mmc0, "fpga:05", MMCI, &mps_mmc0_plat_data);
+AMBA_DEVICE(uart3, "fpga:09", UART3, NULL);
+
+/* DevChip Primecells */
+AMBA_DEVICE(smc, "dev:00", SMC, NULL);
+AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
+AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
+AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
+AMBA_DEVICE(rtc, "dev:e8", RTC, NULL);
+AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
+AMBA_DEVICE(uart1, "dev:f2", UART1, NULL);
+AMBA_DEVICE(uart2, "dev:f3", UART2, NULL);
+AMBA_DEVICE(spi, "dev:f4", SPI, NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+ &mmc0_device,
+ &uart0_device,
+ &uart1_device,
+ &uart2_device,
+ &uart3_device,
+ &smc_device,
+ &clcd_device,
+ &sctl_device,
+ &wdog_device,
+ &rtc_device,
+ &spi_device,
+ &aaci_device,
+};
+
+/*
+ * MPS platform devices
+ */
+static struct resource mps_flash_resource = {
+ .start = MPS_FLASH_BASE,
+ .end = MPS_FLASH_BASE + MPS_FLASH_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource mps_eth_resources[] = {
+ [0] = {
+ .start = MPS_ETH_BASE,
+ .end = MPS_ETH_BASE + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MPS_ETH,
+ .end = IRQ_MPS_ETH,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mps_eth_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mps_eth_resources),
+ .resource = mps_eth_resources,
+};
+
+static void __init gic_init_irq(void)
+{
+ nvic_init();
+}
+
+static void __init timer_init(void)
+{
+ unsigned int timer_irq;
+
+ timer0_va_base = __io_address(MPS_TIMER0_1_BASE);
+ timer1_va_base = __io_address(MPS_TIMER0_1_BASE) + 0x20;
+ timer2_va_base = __io_address(MPS_TIMER2_3_BASE);
+ timer3_va_base = __io_address(MPS_TIMER2_3_BASE) + 0x20;
+
+ timer_irq = IRQ_MPS_TIMER0_1;
+
+ mps_timer_init(timer_irq);
+}
+
+static struct sys_timer mps_timer = {
+ .init = timer_init,
+};
+
+static void __init mps_init(void)
+{
+ int i;
+ clk_register(&mps_clcd_clk);
+
+ mps_flash_register(&mps_flash_resource, 1);
+ platform_device_register(&mps_i2c_device);
+ platform_device_register(&mps_eth_device);
+
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+ struct amba_device *d = amba_devs[i];
+ amba_device_register(d, &iomem_resource);
+ }
+
+#ifdef CONFIG_LEDS
+ leds_event = mps_leds_event;
+#endif
+}
+
+MACHINE_START(MPS, "ARM MPS")
+ .phys_io = MPS_UART0_BASE,
+ .io_pg_offst = (IO_ADDRESS(MPS_UART0_BASE) >> 18) & 0xfffc,
+ .boot_params = PHYS_OFFSET + 0x100,
+ .map_io = mps_map_io,
+ .init_irq = gic_init_irq,
+ .timer = &mps_timer,
+ .init_machine = mps_init,
+MACHINE_END
diff --git a/arch/arm/mach-mps/clock.c b/arch/arm/mach-mps/clock.c
new file mode 100644
index 000000000000..d459efc2c2e2
--- /dev/null
+++ b/arch/arm/mach-mps/clock.c
@@ -0,0 +1,131 @@
+/*
+ * linux/arch/arm/mach-mps/clock.c
+ *
+ * Copyright (C) 2004 ARM Limited.
+ * Written by Deep Blue Solutions Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/hardware/icst307.h>
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+ mutex_lock(&clocks_mutex);
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ mutex_unlock(&clocks_mutex);
+
+ return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EIO;
+
+ if (clk->setvco) {
+ struct icst307_vco vco;
+
+ vco = icst307_khz_to_vco(clk->params, rate / 1000);
+ clk->rate = icst307_khz(clk->params, vco) * 1000;
+
+ clk->setvco(clk, vco);
+ ret = 0;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * These are fixed clocks.
+ */
+static struct clk kmi_clk = {
+ .name = "KMIREFCLK",
+ .rate = 24000000,
+};
+
+static struct clk uart_clk = {
+ .name = "UARTCLK",
+ .rate = 24000000,
+};
+
+static struct clk mmci_clk = {
+ .name = "MCLK",
+ .rate = 24000000,
+};
+
+int clk_register(struct clk *clk)
+{
+ mutex_lock(&clocks_mutex);
+ list_add(&clk->node, &clocks);
+ mutex_unlock(&clocks_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ mutex_lock(&clocks_mutex);
+ list_del(&clk->node);
+ mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static int __init clk_init(void)
+{
+ clk_register(&kmi_clk);
+ clk_register(&uart_clk);
+ clk_register(&mmci_clk);
+ return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-mps/clock.h b/arch/arm/mach-mps/clock.h
new file mode 100644
index 000000000000..dadba695e181
--- /dev/null
+++ b/arch/arm/mach-mps/clock.h
@@ -0,0 +1,25 @@
+/*
+ * linux/arch/arm/mach-realview/clock.h
+ *
+ * Copyright (C) 2004 ARM Limited.
+ * Written by Deep Blue Solutions Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+struct module;
+struct icst307_params;
+
+struct clk {
+ struct list_head node;
+ unsigned long rate;
+ struct module *owner;
+ const char *name;
+ const struct icst307_params *params;
+ void *data;
+ void (*setvco)(struct clk *, struct icst307_vco vco);
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
diff --git a/arch/arm/mach-mps/core.c b/arch/arm/mach-mps/core.c
new file mode 100644
index 000000000000..090b5fe2fa56
--- /dev/null
+++ b/arch/arm/mach-mps/core.c
@@ -0,0 +1,386 @@
+/*
+ * linux/arch/arm/mach-mps/core.c
+ *
+ * Copyright (C) 2009 ARM Limited
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/smsc911x.h>
+#include <linux/ata_platform.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/icst307.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+#include <asm/hardware/gic.h>
+
+#include "clock.h"
+#include "core.h"
+
+#define MPS_REFCOUNTER (__io_address(MPS_SYS_BASE) + MPS_SYS_CNT25MHz_OFFSET)
+
+/*
+ * This is the MPS sched_clock implementation. This has a resolution of 40ns.
+ */
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)readl(MPS_REFCOUNTER) * 40;
+}
+
+#define MPS_FLASHCTRL (__io_address(MPS_SYS_BASE) + MPS_SYS_FLASH_OFFSET)
+
+static struct flash_platform_data mps_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 4,
+};
+
+struct platform_device mps_flash_device = {
+ .name = "armflash",
+ .id = 0,
+ .dev = {
+ .platform_data = &mps_flash_data,
+ },
+};
+
+int mps_flash_register(struct resource *res, u32 num)
+{
+ mps_flash_device.resource = res;
+ mps_flash_device.num_resources = num;
+ return platform_device_register(&mps_flash_device);
+}
+
+static struct smsc911x_platform_config smsc911x_config = {
+ .flags = SMSC911X_USE_32BIT,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device mps_eth_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = 2,
+};
+
+int mps_eth_register(const char *name, struct resource *res)
+{
+ if (name)
+ mps_eth_device.name = name;
+ mps_eth_device.resource = res;
+ if (strcmp(mps_eth_device.name, "smsc911x") == 0)
+ mps_eth_device.dev.platform_data = &smsc911x_config;
+
+ return platform_device_register(&mps_eth_device);
+}
+
+struct platform_device mps_usb_device = {
+ .name = "isp1760",
+ .num_resources = 2,
+};
+
+int mps_usb_register(struct resource *res)
+{
+ mps_usb_device.resource = res;
+ return platform_device_register(&mps_usb_device);
+}
+
+static struct resource mps_i2c_resource = {
+ .start = MPS_I2C_BASE,
+ .end = MPS_I2C_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device mps_i2c_device = {
+ .name = "versatile-i2c",
+ .id = 0,
+ .num_resources = 1,
+ .resource = &mps_i2c_resource,
+};
+
+static struct i2c_board_info mps_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("rtc-ds1307", 0xd0 >> 1),
+ .type = "ds1338",
+ },
+};
+
+static int __init mps_i2c_init(void)
+{
+ return i2c_register_board_info(0, mps_i2c_board_info,
+ ARRAY_SIZE(mps_i2c_board_info));
+}
+arch_initcall(mps_i2c_init);
+
+static unsigned int mps_mmc_status(struct device *dev)
+{
+ return readl(__io_address(MPS_MMCI_BASE)) & 1;
+}
+
+struct mmc_platform_data mps_mmc0_plat_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .status = mps_mmc_status,
+};
+
+struct clk mps_clcd_clk = {
+ .name = "CLCDCLK",
+};
+
+static struct clcd_panel vga = {
+ .mode = {
+ .name = "VGA",
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 39721,
+ .left_margin = 64,
+ .right_margin = 16,
+ .upper_margin = 13,
+ .lower_margin = 3,
+ .hsync_len = 80,
+ .vsync_len = 4,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+ .width = -1,
+ .height = -1,
+ .tim2 = TIM2_BCD | TIM2_IPC,
+ .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+ .bpp = 16,
+};
+
+static int mps_clcd_setup(struct clcd_fb *fb)
+{
+ fb->panel = &vga;
+ fb->fb.fix.smem_start = (unsigned long)MPS_DMC_BASE;
+ fb->fb.screen_base = (char __iomem *)MPS_DMC_BASE;
+ fb->fb.fix.smem_len = 640 * 480 * 2; /* VGA, 16bpp */
+
+ return 0;
+}
+
+static int mps_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(&fb->dev->dev, vma,
+ fb->fb.screen_base,
+ fb->fb.fix.smem_start,
+ fb->fb.fix.smem_len);
+}
+
+static void mps_clcd_remove(struct clcd_fb *fb)
+{
+}
+
+struct clcd_board clcd_plat_data = {
+ .name = "MPS",
+ .check = clcdfb_check,
+ .decode = clcdfb_decode,
+ .setup = mps_clcd_setup,
+ .mmap = mps_clcd_mmap,
+ .remove = mps_clcd_remove,
+};
+
+/*
+ * Where is the timer (VA)?
+ */
+void __iomem *timer0_va_base;
+void __iomem *timer1_va_base;
+void __iomem *timer2_va_base;
+void __iomem *timer3_va_base;
+
+/*
+ * How long is the timer interval?
+ */
+#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
+#if TIMER_INTERVAL >= 0x100000
+#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
+#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
+#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
+#elif TIMER_INTERVAL >= 0x10000
+#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
+#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
+#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
+#else
+#define TIMER_RELOAD (TIMER_INTERVAL)
+#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
+#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
+#endif
+
+static void timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ unsigned long ctrl;
+
+ switch(mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel(TIMER_RELOAD, timer0_va_base + TIMER_LOAD);
+
+ ctrl = TIMER_CTRL_PERIODIC;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set, and timer enabled in 'next_event' hook */
+ ctrl = TIMER_CTRL_ONESHOT;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ ctrl = 0;
+ }
+
+ writel(ctrl, timer0_va_base + TIMER_CTRL);
+}
+
+static int timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long ctrl = readl(timer0_va_base + TIMER_CTRL);
+
+ writel(evt, timer0_va_base + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, timer0_va_base + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device timer0_clockevent = {
+ .name = "timer0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = timer_set_mode,
+ .set_next_event = timer_set_next_event,
+ .rating = 300,
+ .cpumask = CPU_MASK_ALL,
+};
+
+static void __init mps_clockevents_init(unsigned int timer_irq)
+{
+ timer0_clockevent.irq = timer_irq;
+ timer0_clockevent.mult =
+ div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+ timer0_clockevent.max_delta_ns =
+ clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+ timer0_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xf, &timer0_clockevent);
+
+ clockevents_register_device(&timer0_clockevent);
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t mps_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &timer0_clockevent;
+
+ /* clear the interrupt */
+ writel(1, timer0_va_base + TIMER_INTCLR);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mps_timer_irq = {
+ .name = "MPS Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = mps_timer_interrupt,
+};
+
+static cycle_t mps_get_cycles(void)
+{
+ return ~readl(timer3_va_base + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_mps = {
+ .name = "timer3",
+ .rating = 200,
+ .read = mps_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init mps_clocksource_init(void)
+{
+ /* setup timer 0 as free-running clocksource */
+ writel(0, timer3_va_base + TIMER_CTRL);
+ writel(0xffffffff, timer3_va_base + TIMER_LOAD);
+ writel(0xffffffff, timer3_va_base + TIMER_VALUE);
+ writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+ timer3_va_base + TIMER_CTRL);
+
+ clocksource_mps.mult =
+ clocksource_khz2mult(1000, clocksource_mps.shift);
+ clocksource_register(&clocksource_mps);
+}
+
+/*
+ * Set up the clock source and clock events devices
+ */
+void __init mps_timer_init(unsigned int timer_irq)
+{
+ u32 val;
+
+ /*
+ * set clock frequency:
+ * MPS_REFCLK is 32KHz
+ * MPS_TIMCLK is 1MHz
+ */
+ val = readl(__io_address(MPS_SCTL_BASE));
+ writel((MPS_TIMCLK << MPS_TIMER1_EnSel) |
+ (MPS_TIMCLK << MPS_TIMER2_EnSel) |
+ (MPS_TIMCLK << MPS_TIMER3_EnSel) |
+ (MPS_TIMCLK << MPS_TIMER4_EnSel) | val,
+ __io_address(MPS_SCTL_BASE));
+
+ /*
+ * Initialise to a known state (all timers off)
+ */
+ writel(0, timer0_va_base + TIMER_CTRL);
+ writel(0, timer1_va_base + TIMER_CTRL);
+ writel(0, timer2_va_base + TIMER_CTRL);
+ writel(0, timer3_va_base + TIMER_CTRL);
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ setup_irq(timer_irq, &mps_timer_irq);
+
+ mps_clocksource_init();
+ mps_clockevents_init(timer_irq);
+}
diff --git a/arch/arm/mach-mps/core.h b/arch/arm/mach-mps/core.h
new file mode 100644
index 000000000000..051a994acb0d
--- /dev/null
+++ b/arch/arm/mach-mps/core.h
@@ -0,0 +1,69 @@
+/*
+ * linux/arch/arm/mach-mps/core.h
+ *
+ * Copyright (C) 2004 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_MPS_H
+#define __ASM_ARCH_MPS_H
+
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+
+#include <asm/leds.h>
+
+#define AMBA_DEVICE(name,busid,base,plat) \
+static struct amba_device name##_device = { \
+ .dev = { \
+ .coherent_dma_mask = ~0, \
+ .bus_id = busid, \
+ .platform_data = plat, \
+ }, \
+ .res = { \
+ .start = MPS_##base##_BASE, \
+ .end = (MPS_##base##_BASE) + SZ_4K - 1, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ .dma_mask = ~0, \
+ .irq = base##_IRQ, \
+ /* .dma = base##_DMA,*/ \
+}
+
+extern struct platform_device mps_flash_device;
+extern struct platform_device mps_cf_device;
+extern struct platform_device mps_i2c_device;
+extern struct mmc_platform_data mps_mmc0_plat_data;
+extern struct mmc_platform_data mps_mmc1_plat_data;
+extern struct clk mps_clcd_clk;
+extern struct clcd_board clcd_plat_data;
+extern void __iomem *gic_cpu_base_addr;
+#ifdef CONFIG_LOCAL_TIMERS
+extern void __iomem *twd_base;
+#endif
+extern void __iomem *timer0_va_base;
+extern void __iomem *timer1_va_base;
+extern void __iomem *timer2_va_base;
+extern void __iomem *timer3_va_base;
+
+extern void mps_leds_event(led_event_t ledevt);
+extern void mps_timer_init(unsigned int timer_irq);
+extern int mps_flash_register(struct resource *res, u32 num);
+extern int mps_eth_register(const char *name, struct resource *res);
+extern int mps_usb_register(struct resource *res);
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/debug-macro.S b/arch/arm/mach-mps/include/mach/debug-macro.S
new file mode 100644
index 000000000000..eb693a1e672a
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/debug-macro.S
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-mps/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ * Copyright (C) 1994-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+ .macro addruart,rx
+#if 0
+ mov \rx, #0x40000000
+ orr \rx, \rx, #0x00006000
+#else
+ mov \rx, #0x1f000000
+ orr \rx, \rx, #0x00005000
+#endif
+ .endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-mps/include/mach/dma.h b/arch/arm/mach-mps/include/mach/dma.h
new file mode 100644
index 000000000000..291143e64bf1
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/dma.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm/mach-mps/include/mach/dma.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
diff --git a/arch/arm/mach-mps/include/mach/entry-macro.S b/arch/arm/mach-mps/include/mach/entry-macro.S
new file mode 100644
index 000000000000..a531a4ca9100
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/entry-macro.S
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/mach-mps/include/mach/entry-macro.S
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
diff --git a/arch/arm/mach-mps/include/mach/hardware.h b/arch/arm/mach-mps/include/mach/hardware.h
new file mode 100644
index 000000000000..c251699ca806
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/hardware.h
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-mps/include/mach/hardware.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#ifdef CONFIG_MMU
+#error "ARM MPS platform only support !MMU"
+#endif
+
+#define IO_ADDRESS(x) (x)
+#define __io_address(n) __io(IO_ADDRESS(n))
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/io.h b/arch/arm/mach-mps/include/mach/io.h
new file mode 100644
index 000000000000..583850e08d91
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/io.h
@@ -0,0 +1,32 @@
+/*
+ * arch/arm/mach-mps/include/mach/io.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+static inline void __iomem *__io(unsigned long addr)
+{
+ return (void __iomem *)addr;
+}
+
+#define __io(a) __io(a)
+#define __mem_pci(a) (a)
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/irqs.h b/arch/arm/mach-mps/include/mach/irqs.h
new file mode 100644
index 000000000000..eb73a8acf7e7
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/irqs.h
@@ -0,0 +1,49 @@
+/*
+ * arch/arm/mach-mps/include/mach/irqs.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+/*
+ * MPS interrupt sources
+ */
+#define IRQ_MPS_WDOG 0 /* Watchdog timer */
+#define IRQ_MPS_RTC 1 /* Real Time Clock */
+#define IRQ_MPS_TIMER0_1 2 /* Timer 0 and 1 */
+#define IRQ_MPS_TIMER2_3 3 /* Timer 2 and 3 */
+#define IRQ_MPS_MMCIA 4 /* Multimedia Card A */
+#define IRQ_MPS_MMCIB 5 /* Multimedia Card B */
+#define IRQ_MPS_UART0 6 /* UART 0 on development chip */
+#define IRQ_MPS_UART1 7 /* UART 1 on development chip */
+#define IRQ_MPS_UART2 8 /* UART 2 on development chip */
+ /* Reserved */
+#define IRQ_MPS_AACI 10 /* Audio Codec */
+#define IRQ_MPS_CLCD 11 /* CLCD controller */
+#define IRQ_MPS_ETH 12 /* Ethernet controller */
+#define IRQ_MPS_USB 13 /* USB controller */
+#define IRQ_MPS_USB_HC 14 /* USB controller */
+#define IRQ_MPS_CHARLCD 15 /* Character LCD */
+ /* 16 - 29 reserved */
+#define IRQ_MPS_UART3 30 /* UART 3 on development chip */
+#define IRQ_MPS_SPI 31 /* Touchscreen */
+
+#define NR_IRQS 32
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/memory.h b/arch/arm/mach-mps/include/mach/memory.h
new file mode 100644
index 000000000000..bb63833a1ee7
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/memory.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-mps/include/mach/memory.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET UL(0x10000000)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/platform.h b/arch/arm/mach-mps/include/mach/platform.h
new file mode 100644
index 000000000000..78dccb3d6cbe
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/platform.h
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mach-mps/include/mach/platform.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
+
+/*
+ * MPS system registers
+ */
+#define MPS_SYS_BASE 0x40000000
+#define MPS_SYS_ID_OFFSET 0x00 /* Board and FPGA identifier */
+#define MPS_SYS_PERCFG_OFFSET 0x04 /* Peripheral control signals */
+#define MPS_SYS_SW_OFFSET 0x08 /* Indicates user switch settings */
+#define MPS_SYS_LED_OFFSET 0x0C /* Sets LED outputs */
+#define MPS_SYS_7SEG_OFFSET 0x10 /* Sets LED outputs */
+#define MPS_SYS_CNT25MHz_OFFSET 0x14 /* Free running counter incrementing at 25MHz */
+#define MPS_SYS_CNT100Hz_OFFSET 0x18 /* Free running counter incrementing at 100Hz */
+
+/*
+ * MPS peripheral addresses
+ */
+#define MPS_FLASH_BASE 0x18000000
+#define MPS_FLASH_SIZE SZ_64M
+
+#define MPS_SPI_BASE 0x1F004000 /* Touchscreen */
+#define MPS_UART3_BASE 0x1F005000 /* UART 3 */
+
+#define MPS_WATCHDOG_BASE 0x40000000 /* watchdog interface */
+#define MPS_RTC_BASE 0x40001000 /* Real Time Clock */
+#define MPS_TIMER0_1_BASE 0x40002000 /* Timer 0 and 1 */
+#define MPS_TIMER2_3_BASE 0x40003000 /* Timer 2 and 3 */
+#define MPS_SCTL_BASE 0x40004000 /* System controller */
+#define MPS_MMCI_BASE 0x40005000 /* MMC interface */
+#define MPS_UART0_BASE 0x40006000 /* UART 0 */
+#define MPS_UART1_BASE 0x40007000 /* UART 1 */
+#define MPS_UART2_BASE 0x40008000 /* UART 2 */
+ /* Reserved */
+#define MPS_AACI_BASE 0x4000A000 /* Audio */
+#define MPS_I2C_BASE 0x4000B000 /* I2C control */
+#define MPS_CHAR_LCD_BASE 0x4000C000 /* Character LCD */
+
+#define MPS_ETH_BASE 0x4FFE0000 /* Ethernet */
+#define MPS_CLCD_BASE 0x4FFF0000 /* CLCD */
+
+#define MPS_DMC_BASE 0x60000000 /* Dynamic Memory Controller */
+
+#define MPS_SMC_BASE 0xA0000000 /* Static Memory Controller */
+//#define MPS_USB_BASE 0xA0000000 /* USB */
+
+/*
+ * System controller bit assignment
+ */
+#define MPS_REFCLK 0
+#define MPS_TIMCLK 1
+
+#define MPS_TIMER1_EnSel 15
+#define MPS_TIMER2_EnSel 17
+#define MPS_TIMER3_EnSel 19
+#define MPS_TIMER4_EnSel 21
+
+#define MAX_TIMER 2
+#define MAX_PERIOD 699050
+#define TICKS_PER_uSEC 1
+
+/*
+ * These are useconds NOT ticks.
+ */
+#define mSEC_1 1000
+#define mSEC_5 (mSEC_1 * 5)
+#define mSEC_10 (mSEC_1 * 10)
+#define mSEC_25 (mSEC_1 * 25)
+#define SEC_1 (mSEC_1 * 1000)
+
+#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/mach-mps/include/mach/system.h b/arch/arm/mach-mps/include/mach/system.h
new file mode 100644
index 000000000000..e241770e1184
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/system.h
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/mach-mps/include/mach/system.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-mps/include/mach/timex.h b/arch/arm/mach-mps/include/mach/timex.h
new file mode 100644
index 000000000000..91792e8aa490
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/timex.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-mps/include/mach/timex.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define CLOCK_TICK_RATE (50000000 / 16)
diff --git a/arch/arm/mach-mps/include/mach/uncompress.h b/arch/arm/mach-mps/include/mach/uncompress.h
new file mode 100644
index 000000000000..e8eca2e52e99
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/uncompress.h
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-realview/include/mach/uncompress.h
+ *
+ * Copyright (C) 2009 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+
+#include <mach/platform.h>
+
+#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00))
+#define AMBA_UART_LCRH(base) (*(volatile unsigned char *)((base) + 0x2c))
+#define AMBA_UART_CR(base) (*(volatile unsigned char *)((base) + 0x30))
+#define AMBA_UART_FR(base) (*(volatile unsigned char *)((base) + 0x18))
+
+/*
+ * Return the UART base address
+ */
+static inline unsigned long get_uart_base(void)
+{
+ return MPS_UART3_BASE;
+}
+
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+ unsigned long base = get_uart_base();
+
+ while (AMBA_UART_FR(base) & (1 << 5))
+ barrier();
+
+ AMBA_UART_DR(base) = c;
+}
+
+static inline void flush(void)
+{
+ unsigned long base = get_uart_base();
+
+ while (AMBA_UART_FR(base) & (1 << 3))
+ barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-mps/include/mach/vmalloc.h b/arch/arm/mach-mps/include/mach/vmalloc.h
new file mode 100644
index 000000000000..fe0de1b507ac
--- /dev/null
+++ b/arch/arm/mach-mps/include/mach/vmalloc.h
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/mach-realview/include/mach/vmalloc.h
+ *
+ * Copyright (C) 2003 ARM Limited
+ * Copyright (C) 2000 Russell King.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define VMALLOC_END 0xf8000000
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index ad911854eb4c..5ccde7cf39e8 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -7,17 +7,9 @@ config MACH_REALVIEW_EB
help
Include support for the ARM(R) RealView Emulation Baseboard platform.
-config REALVIEW_EB_A9MP
- bool "Support Multicore Cortex-A9"
- depends on MACH_REALVIEW_EB
- select CPU_V7
- help
- Enable support for the Cortex-A9MPCore tile on the Realview platform.
-
config REALVIEW_EB_ARM11MP
bool "Support ARM11MPCore tile"
depends on MACH_REALVIEW_EB
- select CPU_V6
help
Enable support for the ARM11MPCore tile on the Realview platform.
@@ -33,7 +25,6 @@ config REALVIEW_EB_ARM11MP_REVB
config MACH_REALVIEW_PB11MP
bool "Support RealView/PB11MPCore platform"
- select CPU_V6
select ARM_GIC
help
Include support for the ARM(R) RealView MPCore Platform Baseboard.
@@ -42,29 +33,8 @@ config MACH_REALVIEW_PB11MP
config MACH_REALVIEW_PB1176
bool "Support RealView/PB1176 platform"
- select CPU_V6
select ARM_GIC
help
Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
-config MACH_REALVIEW_PBA8
- bool "Support RealView/PB-A8 platform"
- select CPU_V7
- select ARM_GIC
- help
- Include support for the ARM(R) RealView Cortex-A8 Platform Baseboard.
- PB-A8 is a platform with an on-board Cortex-A8 and has support for
- PCI-E and Compact Flash.
-
-config REALVIEW_HIGH_PHYS_OFFSET
- bool "High physical base address for the RealView platform"
- depends on !MACH_REALVIEW_PB1176
- default y
- help
- RealView boards other than PB1176 have the RAM available at
- 0x70000000, 256MB of which being mirrored at 0x00000000. If
- the board supports 512MB of RAM, this option allows the
- memory to be accessed contiguously at the high physical
- offset.
-
endmenu
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 7bea8ffc4b59..d2ae077431dd 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -6,6 +6,5 @@ obj-y := core.o clock.o
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
-obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index bd2aa4f16141..2f04d54711e7 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -28,14 +28,11 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
-#include <linux/smc911x.h>
-#include <asm/clkdev.h>
#include <asm/system.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/leds.h>
-#include <asm/mach-types.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst307.h>
@@ -52,7 +49,7 @@
#define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
-/* used by entry-macro.S and platsmp.c */
+/* used by entry-macro.S */
void __iomem *gic_cpu_base_addr;
/*
@@ -127,29 +124,6 @@ int realview_flash_register(struct resource *res, u32 num)
return platform_device_register(&realview_flash_device);
}
-static struct smc911x_platdata realview_smc911x_platdata = {
- .flags = SMC911X_USE_32BIT,
- .irq_flags = IRQF_SHARED,
- .irq_polarity = 1,
-};
-
-static struct platform_device realview_eth_device = {
- .name = "smc911x",
- .id = 0,
- .num_resources = 2,
-};
-
-int realview_eth_register(const char *name, struct resource *res)
-{
- if (name)
- realview_eth_device.name = name;
- realview_eth_device.resource = res;
- if (strcmp(realview_eth_device.name, "smc911x") == 0)
- realview_eth_device.dev.platform_data = &realview_smc911x_platdata;
-
- return platform_device_register(&realview_eth_device);
-}
-
static struct resource realview_i2c_resource = {
.start = REALVIEW_I2C_BASE,
.end = REALVIEW_I2C_BASE + SZ_4K - 1,
@@ -203,14 +177,9 @@ static const struct icst307_params realview_oscvco_params = {
static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
{
void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
- void __iomem *sys_osc;
+ void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
u32 val;
- if (machine_is_realview_pb1176())
- sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET;
- else
- sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
-
val = readl(sys_osc) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
@@ -219,60 +188,13 @@ static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
writel(0, sys_lock);
}
-static struct clk oscvco_clk = {
+struct clk realview_clcd_clk = {
+ .name = "CLCDCLK",
.params = &realview_oscvco_params,
.setvco = realview_oscvco_set,
};
/*
- * These are fixed clocks.
- */
-static struct clk ref24_clk = {
- .rate = 24000000,
-};
-
-static struct clk_lookup lookups[] = {
- { /* UART0 */
- .dev_id = "dev:f1",
- .clk = &ref24_clk,
- }, { /* UART1 */
- .dev_id = "dev:f2",
- .clk = &ref24_clk,
- }, { /* UART2 */
- .dev_id = "dev:f3",
- .clk = &ref24_clk,
- }, { /* UART3 */
- .dev_id = "fpga:09",
- .clk = &ref24_clk,
- }, { /* KMI0 */
- .dev_id = "fpga:06",
- .clk = &ref24_clk,
- }, { /* KMI1 */
- .dev_id = "fpga:07",
- .clk = &ref24_clk,
- }, { /* MMC0 */
- .dev_id = "fpga:05",
- .clk = &ref24_clk,
- }, { /* EB:CLCD */
- .dev_id = "dev:20",
- .clk = &oscvco_clk,
- }, { /* PB:CLCD */
- .dev_id = "issp:20",
- .clk = &oscvco_clk,
- }
-};
-
-static int __init clk_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
- return 0;
-}
-arch_initcall(clk_init);
-
-/*
* CLCD support.
*/
#define SYS_CLCD_NLCDIOON (1 << 2)
@@ -304,30 +226,7 @@ static struct clcd_panel vga = {
.width = -1,
.height = -1,
.tim2 = TIM2_BCD | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
- .bpp = 16,
-};
-
-static struct clcd_panel xvga = {
- .mode = {
- .name = "XVGA",
- .refresh = 60,
- .xres = 1024,
- .yres = 768,
- .pixclock = 15748,
- .left_margin = 152,
- .right_margin = 48,
- .upper_margin = 23,
- .lower_margin = 3,
- .hsync_len = 104,
- .vsync_len = 4,
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- },
- .width = -1,
- .height = -1,
- .tim2 = TIM2_BCD | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+ .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
.bpp = 16,
};
@@ -350,7 +249,7 @@ static struct clcd_panel sanyo_3_8_in = {
.width = -1,
.height = -1,
.tim2 = TIM2_BCD,
- .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+ .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
.bpp = 16,
};
@@ -373,7 +272,7 @@ static struct clcd_panel sanyo_2_5_in = {
.width = -1,
.height = -1,
.tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+ .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
.bpp = 16,
};
@@ -396,7 +295,7 @@ static struct clcd_panel epson_2_2_in = {
.width = -1,
.height = -1,
.tim2 = TIM2_BCD | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+ .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
.bpp = 16,
};
@@ -409,15 +308,9 @@ static struct clcd_panel epson_2_2_in = {
static struct clcd_panel *realview_clcd_panel(void)
{
void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
- struct clcd_panel *vga_panel;
- struct clcd_panel *panel;
+ struct clcd_panel *panel = &vga;
u32 val;
- if (machine_is_realview_eb())
- vga_panel = &vga;
- else
- vga_panel = &xvga;
-
val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
if (val == SYS_CLCD_ID_SANYO_3_8)
panel = &sanyo_3_8_in;
@@ -426,11 +319,11 @@ static struct clcd_panel *realview_clcd_panel(void)
else if (val == SYS_CLCD_ID_EPSON_2_2)
panel = &epson_2_2_in;
else if (val == SYS_CLCD_ID_VGA)
- panel = vga_panel;
+ panel = &vga;
else {
printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
val);
- panel = vga_panel;
+ panel = &vga;
}
return panel;
@@ -465,18 +358,12 @@ static void realview_clcd_enable(struct clcd_fb *fb)
writel(val, sys_clcd);
}
+static unsigned long framesize = SZ_1M;
+
static int realview_clcd_setup(struct clcd_fb *fb)
{
- unsigned long framesize;
dma_addr_t dma;
- if (machine_is_realview_eb())
- /* VGA, 16bpp */
- framesize = 640 * 480 * 2;
- else
- /* XVGA, 16bpp */
- framesize = 1024 * 768 * 2;
-
fb->panel = realview_clcd_panel();
fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
@@ -624,7 +511,7 @@ static struct clock_event_device timer0_clockevent = {
.set_mode = timer_set_mode,
.set_next_event = timer_set_next_event,
.rating = 300,
- .cpumask = cpu_all_mask,
+ .cpumask = CPU_MASK_ALL,
};
static void __init realview_clockevents_init(unsigned int timer_irq)
@@ -701,7 +588,7 @@ void __init realview_timer_init(unsigned int timer_irq)
* The dummy clock device has to be registered before the main device
* so that the latter will broadcast the clock events
*/
- local_timer_setup();
+ local_timer_setup(smp_processor_id());
#endif
/*
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 44269b162d49..3cea92c70d8f 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -31,7 +31,7 @@
static struct amba_device name##_device = { \
.dev = { \
.coherent_dma_mask = ~0, \
- .init_name = busid, \
+ .bus_id = busid, \
.platform_data = plat, \
}, \
.res = { \
@@ -48,10 +48,12 @@ extern struct platform_device realview_flash_device;
extern struct platform_device realview_i2c_device;
extern struct mmc_platform_data realview_mmc0_plat_data;
extern struct mmc_platform_data realview_mmc1_plat_data;
+extern struct clk realview_clcd_clk;
extern struct clcd_board clcd_plat_data;
extern void __iomem *gic_cpu_base_addr;
#ifdef CONFIG_LOCAL_TIMERS
-extern void __iomem *twd_base;
+extern void __iomem *twd_base_addr;
+extern unsigned int twd_size;
#endif
extern void __iomem *timer0_va_base;
extern void __iomem *timer1_va_base;
@@ -61,6 +63,5 @@ extern void __iomem *timer3_va_base;
extern void realview_leds_event(led_event_t ledevt);
extern void realview_timer_init(unsigned int timer_irq);
extern int realview_flash_register(struct resource *res, u32 num);
-extern int realview_eth_register(const char *name, struct resource *res);
#endif
diff --git a/arch/arm/mach-realview/include/mach/debug-macro.S b/arch/arm/mach-realview/include/mach/debug-macro.S
index 92dbcb9e1792..7196bcadff0c 100644
--- a/arch/arm/mach-realview/include/mach/debug-macro.S
+++ b/arch/arm/mach-realview/include/mach/debug-macro.S
@@ -8,36 +8,15 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- */
-
-#if defined(CONFIG_MACH_REALVIEW_EB) || \
- defined(CONFIG_MACH_REALVIEW_PB11MP) || \
- defined(CONFIG_MACH_REALVIEW_PBA8)
-#ifndef DEBUG_LL_UART_OFFSET
-#define DEBUG_LL_UART_OFFSET 0x00009000
-#elif DEBUG_LL_UART_OFFSET != 0x00009000
-#warning "DEBUG_LL_UART_OFFSET already defined to a different value"
-#endif
-#endif
-
-#ifdef CONFIG_MACH_REALVIEW_PB1176
-#ifndef DEBUG_LL_UART_OFFSET
-#define DEBUG_LL_UART_OFFSET 0x0010c000
-#elif DEBUG_LL_UART_OFFSET != 0x0010c000
-#warning "DEBUG_LL_UART_OFFSET already defined to a different value"
-#endif
-#endif
-
-#ifndef DEBUG_LL_UART_OFFSET
-#error "Unknown RealView platform"
-#endif
+ *
+*/
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
moveq \rx, #0x10000000
- movne \rx, #0xfb000000 @ virtual base
- orr \rx, \rx, #DEBUG_LL_UART_OFFSET
+ movne \rx, #0xf0000000 @ virtual base
+ orr \rx, \rx, #0x00009000
.endm
#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-realview/include/mach/hardware.h b/arch/arm/mach-realview/include/mach/hardware.h
index b42c14f89acb..79a93b3dfca9 100644
--- a/arch/arm/mach-realview/include/mach/hardware.h
+++ b/arch/arm/mach-realview/include/mach/hardware.h
@@ -25,14 +25,7 @@
#include <asm/sizes.h>
/* macro to get at IO space when running virtually */
-/*
- * Statically mapped addresses:
- *
- * 10xx xxxx -> fbxx xxxx
- * 1exx xxxx -> fdxx xxxx
- * 1fxx xxxx -> fexx xxxx
- */
-#define IO_ADDRESS(x) (((x) & 0x03ffffff) + 0xfb000000)
+#define IO_ADDRESS(x) (((x) & 0x0fffffff) + 0xf0000000)
#define __io_address(n) __io(IO_ADDRESS(n))
#endif
diff --git a/arch/arm/mach-realview/include/mach/irqs.h b/arch/arm/mach-realview/include/mach/irqs.h
index fe5cb987aa21..02a918529db3 100644
--- a/arch/arm/mach-realview/include/mach/irqs.h
+++ b/arch/arm/mach-realview/include/mach/irqs.h
@@ -25,7 +25,6 @@
#include <mach/board-eb.h>
#include <mach/board-pb11mp.h>
#include <mach/board-pb1176.h>
-#include <mach/board-pba8.h>
#define IRQ_LOCALTIMER 29
#define IRQ_LOCALWDOG 30
diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h
index 293c30025e7e..0e673483a141 100644
--- a/arch/arm/mach-realview/include/mach/memory.h
+++ b/arch/arm/mach-realview/include/mach/memory.h
@@ -23,10 +23,16 @@
/*
* Physical DRAM offset.
*/
-#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
-#define PHYS_OFFSET UL(0x70000000)
-#else
#define PHYS_OFFSET UL(0x00000000)
-#endif
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
+#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
#endif
diff --git a/arch/arm/mach-realview/include/mach/uncompress.h b/arch/arm/mach-realview/include/mach/uncompress.h
index 415d634d52ab..79f50f218e77 100644
--- a/arch/arm/mach-realview/include/mach/uncompress.h
+++ b/arch/arm/mach-realview/include/mach/uncompress.h
@@ -23,7 +23,6 @@
#include <mach/board-eb.h>
#include <mach/board-pb11mp.h>
#include <mach/board-pb1176.h>
-#include <mach/board-pba8.h>
#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00))
#define AMBA_UART_LCRH(base) (*(volatile unsigned char *)((base) + 0x2c))
@@ -41,8 +40,6 @@ static inline unsigned long get_uart_base(void)
return REALVIEW_PB11MP_UART0_BASE;
else if (machine_is_realview_pb1176())
return REALVIEW_PB1176_UART0_BASE;
- else if (machine_is_realview_pba8())
- return REALVIEW_PBA8_UART0_BASE;
else
return 0;
}
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index 67d6d9cc68b2..44d178cd5733 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -38,14 +38,18 @@ void local_timer_interrupt(void)
#ifdef CONFIG_LOCAL_TIMERS
+#define TWD_BASE(cpu) (twd_base_addr + (cpu) * twd_size)
+
/* set up by the platform code */
-void __iomem *twd_base;
+void __iomem *twd_base_addr;
+unsigned int twd_size;
static unsigned long mpcore_timer_rate;
static void local_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
+ void __iomem *base = TWD_BASE(smp_processor_id());
unsigned long ctrl;
switch(mode) {
@@ -64,16 +68,17 @@ static void local_timer_set_mode(enum clock_event_mode mode,
ctrl = 0;
}
- __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
+ __raw_writel(ctrl, base + TWD_TIMER_CONTROL);
}
static int local_timer_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
- unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
+ void __iomem *base = TWD_BASE(smp_processor_id());
+ unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL);
- __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
- __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);
+ __raw_writel(evt, base + TWD_TIMER_COUNTER);
+ __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL);
return 0;
}
@@ -86,16 +91,19 @@ static int local_timer_set_next_event(unsigned long evt,
*/
int local_timer_ack(void)
{
- if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
- __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
+ void __iomem *base = TWD_BASE(smp_processor_id());
+
+ if (__raw_readl(base + TWD_TIMER_INTSTAT)) {
+ __raw_writel(1, base + TWD_TIMER_INTSTAT);
return 1;
}
return 0;
}
-static void __cpuinit twd_calibrate_rate(void)
+static void __cpuinit twd_calibrate_rate(unsigned int cpu)
{
+ void __iomem *base = TWD_BASE(cpu);
unsigned long load, count;
u64 waitjiffies;
@@ -116,15 +124,15 @@ static void __cpuinit twd_calibrate_rate(void)
waitjiffies += 5;
/* enable, no interrupt or reload */
- __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
+ __raw_writel(0x1, base + TWD_TIMER_CONTROL);
/* maximum value */
- __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
+ __raw_writel(0xFFFFFFFFU, base + TWD_TIMER_COUNTER);
while (get_jiffies_64() < waitjiffies)
udelay(10);
- count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
+ count = __raw_readl(base + TWD_TIMER_COUNTER);
mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
@@ -134,19 +142,18 @@ static void __cpuinit twd_calibrate_rate(void)
load = mpcore_timer_rate / HZ;
- __raw_writel(load, twd_base + TWD_TIMER_LOAD);
+ __raw_writel(load, base + TWD_TIMER_LOAD);
}
/*
* Setup the local clock events for a CPU.
*/
-void __cpuinit local_timer_setup(void)
+void __cpuinit local_timer_setup(unsigned int cpu)
{
- unsigned int cpu = smp_processor_id();
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
unsigned long flags;
- twd_calibrate_rate();
+ twd_calibrate_rate(cpu);
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
@@ -154,7 +161,7 @@ void __cpuinit local_timer_setup(void)
clk->set_mode = local_timer_set_mode;
clk->set_next_event = local_timer_set_next_event;
clk->irq = IRQ_LOCALTIMER;
- clk->cpumask = cpumask_of(cpu);
+ clk->cpumask = cpumask_of_cpu(cpu);
clk->shift = 20;
clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
@@ -171,9 +178,9 @@ void __cpuinit local_timer_setup(void)
/*
* take a local timer down
*/
-void __cpuexit local_timer_stop(void)
+void __cpuexit local_timer_stop(unsigned int cpu)
{
- __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
+ __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
}
#else /* CONFIG_LOCAL_TIMERS */
@@ -183,9 +190,8 @@ static void dummy_timer_set_mode(enum clock_event_mode mode,
{
}
-void __cpuinit local_timer_setup(void)
+void __cpuinit local_timer_setup(unsigned int cpu)
{
- unsigned int cpu = smp_processor_id();
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
clk->name = "dummy_timer";
@@ -193,7 +199,7 @@ void __cpuinit local_timer_setup(void)
clk->rating = 200;
clk->set_mode = dummy_timer_set_mode;
clk->broadcast = smp_timer_broadcast;
- clk->cpumask = cpumask_of(cpu);
+ clk->cpumask = cpumask_of_cpu(cpu);
clockevents_register_device(clk);
}
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index ea3c75595fa9..e102aeb0f76e 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -12,7 +12,6 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
@@ -24,8 +23,6 @@
#include <mach/board-pb11mp.h>
#include <mach/scu.h>
-#include "core.h"
-
extern void realview_secondary_startup(void);
/*
@@ -34,20 +31,15 @@ extern void realview_secondary_startup(void);
*/
volatile int __cpuinitdata pen_release = -1;
-static void __iomem *scu_base_addr(void)
-{
- if (machine_is_realview_eb_mp())
- return __io_address(REALVIEW_EB11MP_SCU_BASE);
- else if (machine_is_realview_pb11mp())
- return __io_address(REALVIEW_TC11MP_SCU_BASE);
- else
- return (void __iomem *)0;
-}
-
static unsigned int __init get_core_count(void)
{
unsigned int ncores;
- void __iomem *scu_base = scu_base_addr();
+ void __iomem *scu_base = 0;
+
+ if (machine_is_realview_eb() && core_tile_eb11mp())
+ scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
+ else if (machine_is_realview_pb11mp())
+ scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
if (scu_base) {
ncores = __raw_readl(scu_base + SCU_CONFIG);
@@ -64,7 +56,14 @@ static unsigned int __init get_core_count(void)
static void scu_enable(void)
{
u32 scu_ctrl;
- void __iomem *scu_base = scu_base_addr();
+ void __iomem *scu_base;
+
+ if (machine_is_realview_eb() && core_tile_eb11mp())
+ scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
+ else if (machine_is_realview_pb11mp())
+ scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
+ else
+ BUG();
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
scu_ctrl |= 1;
@@ -89,7 +88,10 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
* core (e.g. timer irq), then they will not have been enabled
* for us: do so
*/
- gic_cpu_init(0, gic_cpu_base_addr);
+ if (machine_is_realview_eb() && core_tile_eb11mp())
+ gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
+ else if (machine_is_realview_pb11mp())
+ gic_cpu_init(0, __io_address(REALVIEW_TC11MP_GIC_CPU_BASE));
/*
* let the primary processor know we're out of the
@@ -230,7 +232,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
* dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
* realview_timer_init
*/
- local_timer_setup();
+ if ((machine_is_realview_eb() && core_tile_eb11mp()) ||
+ machine_is_realview_pb11mp())
+ local_timer_setup(cpu);
#endif
/*
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index bed39ed97613..eb829eb1ebe2 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -108,7 +108,7 @@ static struct map_desc realview_eb11mp_io_desc[] __initdata = {
static void __init realview_eb_map_io(void)
{
iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
- if (core_tile_eb11mp() || core_tile_a9mp())
+ if (core_tile_eb11mp())
iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
}
@@ -242,6 +242,12 @@ static struct resource realview_eb_eth_resources[] = {
},
};
+static struct platform_device realview_eb_eth_device = {
+ .id = 0,
+ .num_resources = ARRAY_SIZE(realview_eb_eth_resources),
+ .resource = realview_eb_eth_resources,
+};
+
/*
* Detect and register the correct Ethernet device. RealView/EB rev D
* platforms use the newer SMSC LAN9118 Ethernet chip
@@ -249,24 +255,26 @@ static struct resource realview_eb_eth_resources[] = {
static int eth_device_register(void)
{
void __iomem *eth_addr = ioremap(REALVIEW_EB_ETH_BASE, SZ_4K);
- const char *name = NULL;
u32 idrev;
if (!eth_addr)
return -ENOMEM;
idrev = readl(eth_addr + 0x50);
- if ((idrev & 0xFFFF0000) != 0x01180000)
- /* SMSC LAN9118 not present, use LAN91C111 instead */
- name = "smc91x";
+ if ((idrev & 0xFFFF0000) == 0x01180000)
+ /* SMSC LAN9118 chip present */
+ realview_eb_eth_device.name = "smc911x";
+ else
+ /* SMSC 91C111 chip present */
+ realview_eb_eth_device.name = "smc91x";
iounmap(eth_addr);
- return realview_eth_register(name, realview_eb_eth_resources);
+ return platform_device_register(&realview_eb_eth_device);
}
static void __init gic_init_irq(void)
{
- if (core_tile_eb11mp() || core_tile_a9mp()) {
+ if (core_tile_eb11mp()) {
unsigned int pldctrl;
/* new irq mode */
@@ -334,9 +342,10 @@ static void __init realview_eb_timer_init(void)
timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE);
timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
- if (core_tile_eb11mp() || core_tile_a9mp()) {
+ if (core_tile_eb11mp()) {
#ifdef CONFIG_LOCAL_TIMERS
- twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE);
+ twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE);
+ twd_size = REALVIEW_EB11MP_TWD_SIZE;
#endif
timer_irq = IRQ_EB11MP_TIMER0_1;
} else
@@ -353,7 +362,7 @@ static void __init realview_eb_init(void)
{
int i;
- if (core_tile_eb11mp() || core_tile_a9mp()) {
+ if (core_tile_eb11mp()) {
realview_eb11mp_fixup();
#ifdef CONFIG_CACHE_L2X0
@@ -363,6 +372,8 @@ static void __init realview_eb_init(void)
#endif
}
+ clk_register(&realview_clcd_clk);
+
realview_flash_register(&realview_eb_flash_resource, 1);
platform_device_register(&realview_i2c_device);
eth_device_register();
@@ -381,7 +392,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
.phys_io = REALVIEW_EB_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
- .boot_params = PHYS_OFFSET + 0x00000100,
+ .boot_params = 0x00000100,
.map_io = realview_eb_map_io,
.init_irq = gic_init_irq,
.timer = &realview_eb_timer,
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 8f0683c22140..cccdb3eb90fe 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -222,6 +222,13 @@ static struct resource realview_pb1176_smsc911x_resources[] = {
},
};
+static struct platform_device realview_pb1176_smsc911x_device = {
+ .name = "smc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(realview_pb1176_smsc911x_resources),
+ .resource = realview_pb1176_smsc911x_resources,
+};
+
static void __init gic_init_irq(void)
{
/* ARM1176 DevChip GIC, primary */
@@ -258,8 +265,10 @@ static void __init realview_pb1176_init(void)
l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
#endif
+ clk_register(&realview_clcd_clk);
+
realview_flash_register(&realview_pb1176_flash_resource, 1);
- realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
+ platform_device_register(&realview_pb1176_smsc911x_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
@@ -275,7 +284,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
.phys_io = REALVIEW_PB1176_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
- .boot_params = PHYS_OFFSET + 0x00000100,
+ .boot_params = 0x00000100,
.map_io = realview_pb1176_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pb1176_timer,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 3ebdb2dadd6f..8b863148ec18 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -230,6 +230,13 @@ static struct resource realview_pb11mp_smsc911x_resources[] = {
},
};
+static struct platform_device realview_pb11mp_smsc911x_device = {
+ .name = "smc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(realview_pb11mp_smsc911x_resources),
+ .resource = realview_pb11mp_smsc911x_resources,
+};
+
struct resource realview_pb11mp_cf_resources[] = {
[0] = {
.start = REALVIEW_PB11MP_CF_BASE,
@@ -285,7 +292,8 @@ static void __init realview_pb11mp_timer_init(void)
timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
#ifdef CONFIG_LOCAL_TIMERS
- twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE);
+ twd_base_addr = __io_address(REALVIEW_TC11MP_TWD_BASE);
+ twd_size = REALVIEW_TC11MP_TWD_SIZE;
#endif
realview_timer_init(IRQ_TC11MP_TIMER0_1);
}
@@ -304,9 +312,11 @@ static void __init realview_pb11mp_init(void)
l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff);
#endif
+ clk_register(&realview_clcd_clk);
+
realview_flash_register(realview_pb11mp_flash_resource,
ARRAY_SIZE(realview_pb11mp_flash_resource));
- realview_eth_register(NULL, realview_pb11mp_smsc911x_resources);
+ platform_device_register(&realview_pb11mp_smsc911x_device);
platform_device_register(&realview_i2c_device);
platform_device_register(&realview_pb11mp_cf_device);
@@ -324,7 +334,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
.phys_io = REALVIEW_PB11MP_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
- .boot_params = PHYS_OFFSET + 0x00000100,
+ .boot_params = 0x00000100,
.map_io = realview_pb11mp_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pb11mp_timer,
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 1c43494f5c42..15b0434c1237 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -335,11 +335,25 @@ static struct resource versatile_i2c_resource = {
static struct platform_device versatile_i2c_device = {
.name = "versatile-i2c",
- .id = -1,
+ .id = 0,
.num_resources = 1,
.resource = &versatile_i2c_resource,
};
+static struct i2c_board_info versatile_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("rtc-ds1307", 0xd0 >> 1),
+ .type = "ds1338",
+ },
+};
+
+static int __init versatile_i2c_init(void)
+{
+ return i2c_register_board_info(0, versatile_i2c_board_info,
+ ARRAY_SIZE(versatile_i2c_board_info));
+}
+arch_initcall(versatile_i2c_init);
+
#define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)
unsigned int mmc_status(struct device *dev)
@@ -455,12 +469,12 @@ static struct clcd_panel vga = {
.xres = 640,
.yres = 480,
.pixclock = 39721,
- .left_margin = 40,
- .right_margin = 24,
- .upper_margin = 32,
- .lower_margin = 11,
- .hsync_len = 96,
- .vsync_len = 2,
+ .left_margin = 64,
+ .right_margin = 16,
+ .upper_margin = 13,
+ .lower_margin = 3,
+ .hsync_len = 80,
+ .vsync_len = 4,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
},
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 91a76f472c24..42e1059505a2 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -362,7 +362,10 @@ config CPU_FEROCEON_OLD_ID
# ARMv6
config CPU_V6
- bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+ bool "Support ARM V6 processor"
+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX
+ default y if ARCH_MX3
+ default y if ARCH_MSM
select CPU_32v6
select CPU_ABRT_EV6
select CPU_PABRT_NOIFAR
@@ -387,7 +390,8 @@ config CPU_32v6K
# ARMv7
config CPU_V7
- bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+ bool "Support ARM V7 processor"
+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3 || MACH_REALVIEW_PBA8 || MACH_REALVIEW_PBX
select CPU_32v6K
select CPU_32v7
select CPU_ABRT_EV7
@@ -399,6 +403,19 @@ config CPU_V7
select CPU_COPY_V6 if MMU
select CPU_TLB_V7 if MMU
+# ARMv7
+config CPU_V7M
+ bool "Support ARMv7-M processors"
+ depends on MACH_MPS
+ select THUMB2_KERNEL
+ select ARM_THUMB
+ select CPU_32v7M
+ select CPU_32v6K
+ select CPU_ABRT_EV7M
+ select CPU_PABRT_NOIFAR
+ select CPU_CACHE_V7M
+ select CPU_CACHE_VIPT
+
# Figure out what processor architecture version we should be using.
# This defines the compiler instruction set which depends on the machine type.
config CPU_32v3
@@ -428,6 +445,9 @@ config CPU_32v6
config CPU_32v7
bool
+config CPU_32v7M
+ bool
+
# The abort model
config CPU_ABRT_NOMMU
bool
@@ -453,6 +473,9 @@ config CPU_ABRT_EV6
config CPU_ABRT_EV7
bool
+config CPU_ABRT_EV7M
+ bool
+
config CPU_PABRT_IFAR
bool
@@ -478,12 +501,20 @@ config CPU_CACHE_V6
config CPU_CACHE_V7
bool
+config CPU_CACHE_V7M
+ bool
+
config CPU_CACHE_VIVT
bool
config CPU_CACHE_VIPT
bool
+config CPU_NO_CACHE_BCAST
+ bool
+ depends on SMP
+ default y if CPU_V6
+
if MMU
# The copy-page model
config CPU_COPY_V3
@@ -569,7 +600,7 @@ comment "Processor Features"
config ARM_THUMB
bool "Support Thumb user binaries"
- depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON
+ depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON || CPU_V7M
default y
help
Say Y if you want to include kernel support for running user space
@@ -597,6 +628,20 @@ config CPU_BIG_ENDIAN
port must properly enable any big-endian related features
of your chipset/board/processor.
+config CPU_ENDIAN_BE8
+ bool
+ depends on CPU_BIG_ENDIAN
+ default CPU_V6 || CPU_V7
+ help
+ Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors.
+
+config CPU_ENDIAN_BE32
+ bool
+ depends on CPU_BIG_ENDIAN
+ default !CPU_ENDIAN_BE8
+ help
+ Support for the BE-32 (big-endian) mode on pre-ARMv6 processors.
+
config CPU_HIGH_VECTOR
depends on !MMU && CPU_CP15 && !CPU_ARM740T
bool "Select the High exception vector"
@@ -704,7 +749,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
config CACHE_L2X0
bool "Enable the L2x0 outer cache controller"
- depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP
+ depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP || MACH_REALVIEW_PBX
default y
select OUTER_CACHE
help
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 480f78a3611a..9d99f79c8b6c 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_CPU_ABRT_EV5T) += abort-ev5t.o
obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o
obj-$(CONFIG_CPU_ABRT_EV6) += abort-ev6.o
obj-$(CONFIG_CPU_ABRT_EV7) += abort-ev7.o
+obj-$(CONFIG_CPU_ABRT_EV7M) += abort-ev7m.o
obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o
obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o
@@ -73,6 +74,7 @@ obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
obj-$(CONFIG_CPU_V7) += proc-v7.o
+obj-$(CONFIG_CPU_V7M) += proc-v7m.o
obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
index 94077fbd96b7..f332df7f0d37 100644
--- a/arch/arm/mm/abort-ev6.S
+++ b/arch/arm/mm/abort-ev6.S
@@ -29,14 +29,17 @@ ENTRY(v6_early_abort)
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
/*
- * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR.
+ * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR (erratum 326103).
* The test below covers all the write situations, including Java bytecodes
*/
- bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
+ bic r1, r1, #1 << 11 @ clear bit 11 of FSR
tst r3, #PSR_J_BIT @ Java?
movne pc, lr
do_thumb_abort
ldreq r3, [r2] @ read aborted ARM instruction
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ reveq r3, r3
+#endif
do_ldrd_abort
tst r3, #1 << 20 @ L = 0 -> write
orreq r1, r1, #1 << 11 @ yes.
diff --git a/arch/arm/mm/abort-ev7m.S b/arch/arm/mm/abort-ev7m.S
new file mode 100644
index 000000000000..083e85b27850
--- /dev/null
+++ b/arch/arm/mm/abort-ev7m.S
@@ -0,0 +1,9 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v7m_early_abort
+ */
+ .align 5
+ENTRY(v7m_early_abort)
+ mov pc, lr
+ENDPROC(v7m_early_abort)
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 3a398befed41..b270d6228fe2 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -62,6 +62,12 @@
#define SHIFT_ASR 0x40
#define SHIFT_RORRRX 0x60
+#define BAD_INSTR 0xdeadc0de
+
+/* Thumb-2 32 bit format per ARMv7 DDI0406A A6.3, either f800h,e800h,f800h */
+#define IS_T32(hi16) \
+ (((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800))
+
static unsigned long ai_user;
static unsigned long ai_sys;
static unsigned long ai_skipped;
@@ -153,7 +159,9 @@ union offset_union {
#define __get8_unaligned_check(ins,val,addr,err) \
__asm__( \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
@@ -209,7 +217,9 @@ union offset_union {
do { \
unsigned int err = 0, v = val, a = addr; \
__asm__( FIRST_BYTE_16 \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
"2: "ins" %1, [%2]\n" \
"3:\n" \
@@ -239,11 +249,17 @@ union offset_union {
do { \
unsigned int err = 0, v = val, a = addr; \
__asm__( FIRST_BYTE_32 \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
- "2: "ins" %1, [%2], #1\n" \
+ ARM( "2: "ins" %1, [%2], #1\n" ) \
+ THUMB( "2: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
- "3: "ins" %1, [%2], #1\n" \
+ ARM( "3: "ins" %1, [%2], #1\n" ) \
+ THUMB( "3: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
"4: "ins" %1, [%2]\n" \
"5:\n" \
@@ -332,38 +348,48 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
struct pt_regs *regs)
{
unsigned int rd = RD_BITS(instr);
-
- if (((rd & 1) == 1) || (rd == 14))
+ unsigned int rd2;
+ int load;
+
+ if ((instr & 0xfe000000) == 0xe8000000) {
+ /* ARMv7 Thumb-2 32-bit LDRD/STRD */
+ rd2 = (instr >> 8) & 0xf;
+ load = !!(LDST_L_BIT(instr));
+ } else if (((rd & 1) == 1) || (rd == 14))
goto bad;
+ else {
+ load = ((instr & 0xf0) == 0xd0);
+ rd2 = rd + 1;
+ }
ai_dword += 1;
if (user_mode(regs))
goto user;
- if ((instr & 0xf0) == 0xd0) {
+ if (load) {
unsigned long val;
get32_unaligned_check(val, addr);
regs->uregs[rd] = val;
get32_unaligned_check(val, addr + 4);
- regs->uregs[rd + 1] = val;
+ regs->uregs[rd2] = val;
} else {
put32_unaligned_check(regs->uregs[rd], addr);
- put32_unaligned_check(regs->uregs[rd + 1], addr + 4);
+ put32_unaligned_check(regs->uregs[rd2], addr + 4);
}
return TYPE_LDST;
user:
- if ((instr & 0xf0) == 0xd0) {
+ if (load) {
unsigned long val;
get32t_unaligned_check(val, addr);
regs->uregs[rd] = val;
get32t_unaligned_check(val, addr + 4);
- regs->uregs[rd + 1] = val;
+ regs->uregs[rd2] = val;
} else {
put32t_unaligned_check(regs->uregs[rd], addr);
- put32t_unaligned_check(regs->uregs[rd + 1], addr + 4);
+ put32t_unaligned_check(regs->uregs[rd2], addr + 4);
}
return TYPE_LDST;
@@ -616,8 +642,72 @@ thumb2arm(u16 tinstr)
/* Else fall through for illegal instruction case */
default:
- return 0xdeadc0de;
+ return BAD_INSTR;
+ }
+}
+
+/*
+ * Convert Thumb-2 32 bit LDM, STM, LDRD, STRD to equivalent instruction
+ * handlable by ARM alignment handler, also find the corresponding handler,
+ * so that we can reuse ARM userland alignment fault fixups for Thumb.
+ *
+ * @pinstr: original Thumb-2 instruction; returns new handlable instruction
+ * @regs: register context.
+ * @poffset: return offset from faulted addr for later writeback
+ *
+ * NOTES:
+ * 1. Comments below refer to ARMv7 DDI0406A Thumb Instruction sections.
+ * 2. Register name Rt from ARMv7 is same as Rd from ARMv6 (Rd is Rt)
+ */
+static void *
+do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs,
+ union offset_union *poffset)
+{
+ unsigned long instr = *pinstr;
+ u16 tinst1 = (instr >> 16) & 0xffff;
+ u16 tinst2 = instr & 0xffff;
+ poffset->un = 0;
+
+ switch (tinst1 & 0xffe0) {
+ /* A6.3.5 Load/Store multiple */
+ case 0xe880: /* STM/STMIA/STMEA,LDM/LDMIA, PUSH/POP T2 */
+ case 0xe8a0: /* ...above writeback version */
+ case 0xe900: /* STMDB/STMFD, LDMDB/LDMEA */
+ case 0xe920: /* ...above writeback version */
+ /* no need offset decision since handler calculates it */
+ return do_alignment_ldmstm;
+
+ case 0xf840: /* POP/PUSH T3 (single register) */
+ if (RN_BITS(instr) == 13 && (tinst2 & 0x09ff) == 0x0904) {
+ u32 L = !!(LDST_L_BIT(instr));
+ const u32 subset[2] = {
+ 0xe92d0000, /* STMDB sp!,{registers} */
+ 0xe8bd0000, /* LDMIA sp!,{registers} */
+ };
+ *pinstr = subset[L] | (1<<RD_BITS(instr));
+ return do_alignment_ldmstm;
+ }
+ /* Else fall through for illegal instruction case */
+ break;
+
+ /* A6.3.6 Load/store double, STRD/LDRD(immed, lit, reg) */
+ case 0xe860:
+ case 0xe960:
+ case 0xe8e0:
+ case 0xe9e0:
+ poffset->un = (tinst2 & 0xff) << 2;
+ case 0xe940:
+ case 0xe9c0:
+ return do_alignment_ldrdstrd;
+
+ /*
+ * No need to handle load/store instructions up to word size
+ * since ARMv6 and later CPUs can perform unaligned accesses.
+ */
+ default:
+ break;
}
+ return NULL;
}
static int
@@ -630,6 +720,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
mm_segment_t fs;
unsigned int fault;
u16 tinstr = 0;
+ int isize = 4;
+ int thumb2_32b = 0;
instrptr = instruction_pointer(regs);
@@ -637,8 +729,19 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
set_fs(KERNEL_DS);
if (thumb_mode(regs)) {
fault = __get_user(tinstr, (u16 *)(instrptr & ~1));
- if (!(fault))
- instr = thumb2arm(tinstr);
+ if (!fault) {
+ if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
+ IS_T32(tinstr)) {
+ /* Thumb-2 32-bit */
+ u16 tinst2 = 0;
+ fault = __get_user(tinst2, (u16 *)(instrptr+2));
+ instr = (tinstr << 16) | tinst2;
+ thumb2_32b = 1;
+ } else {
+ isize = 2;
+ instr = thumb2arm(tinstr);
+ }
+ }
} else
fault = __get_user(instr, (u32 *)instrptr);
set_fs(fs);
@@ -655,7 +758,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
fixup:
- regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
+ regs->ARM_pc += isize;
switch (CODING_BITS(instr)) {
case 0x00000000: /* 3.13.4 load/store instruction extensions */
@@ -714,18 +817,25 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
handler = do_alignment_ldrstr;
break;
- case 0x08000000: /* ldm or stm */
- handler = do_alignment_ldmstm;
+ case 0x08000000: /* ldm or stm, or thumb-2 32bit instruction */
+ if (thumb2_32b)
+ handler = do_alignment_t32_to_handler(&instr, regs, &offset);
+ else
+ handler = do_alignment_ldmstm;
break;
default:
goto bad;
}
+ if (!handler)
+ goto bad;
type = handler(addr, instr, regs);
- if (type == TYPE_ERROR || type == TYPE_FAULT)
+ if (type == TYPE_ERROR || type == TYPE_FAULT) {
+ regs->ARM_pc -= isize;
goto bad_or_fault;
+ }
if (type == TYPE_LDST)
do_alignment_finish_ldst(addr, instr, regs, offset);
@@ -735,7 +845,6 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
bad_or_fault:
if (type == TYPE_ERROR)
goto bad;
- regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
/*
* We got a fault - fix it up, or die.
*/
@@ -751,8 +860,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
*/
printk(KERN_ERR "Alignment trap: not handling instruction "
"%0*lx at [<%08lx>]\n",
- thumb_mode(regs) ? 4 : 8,
- thumb_mode(regs) ? tinstr : instr, instrptr);
+ isize << 1,
+ isize == 2 ? tinstr : instr, instrptr);
ai_skipped += 1;
return 1;
@@ -763,8 +872,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx "
"Address=0x%08lx FSR 0x%03x\n", current->comm,
task_pid_nr(current), instrptr,
- thumb_mode(regs) ? 4 : 8,
- thumb_mode(regs) ? tinstr : instr,
+ isize << 1,
+ isize == 2 ? tinstr : instr,
addr, fsr);
if (ai_usermode & UM_FIXUP)
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b480f1d3591f..b97081b9cefd 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -27,6 +27,7 @@
static void __iomem *l2x0_base;
static DEFINE_SPINLOCK(l2x0_lock);
+bool l2x0_disabled;
static inline void sync_writel(unsigned long val, unsigned long reg,
unsigned long complete_mask)
@@ -34,7 +35,11 @@ static inline void sync_writel(unsigned long val, unsigned long reg,
unsigned long flags;
spin_lock_irqsave(&l2x0_lock, flags);
+#ifdef CONFIG_ARM_ERRATA_484863
+ asm volatile("swp %0, %0, [%1]\n" : "+r" (val) : "r" (l2x0_base + reg));
+#else
writel(val, l2x0_base + reg);
+#endif
/* wait for the operation to complete */
while (readl(l2x0_base + reg) & complete_mask)
;
@@ -97,20 +102,25 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux;
- l2x0_base = base;
+ if (l2x0_disabled) {
+ printk(KERN_INFO "L2X0 cache controller disabled\n");
+ return;
+ }
- /* disable L2X0 */
- writel(0, l2x0_base + L2X0_CTRL);
+ l2x0_base = base;
- aux = readl(l2x0_base + L2X0_AUX_CTRL);
- aux &= aux_mask;
- aux |= aux_val;
- writel(aux, l2x0_base + L2X0_AUX_CTRL);
+ if (!(readl(l2x0_base + L2X0_CTRL) & 1)) {
+ /* L2X0 cache controller disabled */
+ aux = readl(l2x0_base + L2X0_AUX_CTRL);
+ aux &= aux_mask;
+ aux |= aux_val;
+ writel(aux, l2x0_base + L2X0_AUX_CTRL);
- l2x0_inv_all();
+ l2x0_inv_all();
- /* enable L2X0 */
- writel(1, l2x0_base + L2X0_CTRL);
+ /* enable L2X0 */
+ writel(1, l2x0_base + L2X0_CTRL);
+ }
outer_cache.inv_range = l2x0_inv_range;
outer_cache.clean_range = l2x0_clean_range;
@@ -118,3 +128,10 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
printk(KERN_INFO "L2X0 cache controller enabled\n");
}
+
+static int __init l2x0_disable(char *unused)
+{
+ l2x0_disabled = 1;
+ return 0;
+}
+early_param("nol2x0", l2x0_disable);
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 13936b2750f6..b804c9d3e420 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -12,6 +12,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/unwind.h>
#include "proc-macros.S"
@@ -20,6 +21,39 @@
#define D_CACHE_LINE_SIZE 32
#define BTB_FLUSH_SIZE 8
+#ifdef CONFIG_ARM_ERRATA_411920
+/*
+ * Invalidate the entire I cache (this code is a workaround for the ARM1136
+ * Errata 411920 - Invalidate Instruction Cache operation can fail. This
+ * Errata is present in 1136, 1156 and 1176. It does not affect the MPCore
+ *
+ * Registers:
+ * r0 - set to 0
+ * r1 - corrupted
+ */
+ENTRY(v6_icache_inval_all)
+ mov r0, #0
+ mrs r1, cpsr
+ cpsid ifa @ disable interrupts
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache
+ msr cpsr_cx, r1 @ restore interrupts
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ mov pc, lr
+#endif
+
/*
* v6_flush_cache_all()
*
@@ -31,8 +65,12 @@ ENTRY(v6_flush_kern_cache_all)
mov r0, #0
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate
+#ifndef CONFIG_ARM_ERRATA_411920
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
#else
+ b v6_icache_inval_all
+#endif
+#else
mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate
#endif
mov pc, lr
@@ -92,24 +130,43 @@ ENTRY(v6_coherent_kern_range)
* - the Icache does not read data from the write buffer
*/
ENTRY(v6_coherent_user_range)
-
+ UNWIND(.fnstart )
#ifdef HARVARD_CACHE
bic r0, r0, #CACHE_LINE_SIZE - 1
-1: mcr p15, 0, r0, c7, c10, 1 @ clean D line
+1:
+ USER( mcr p15, 0, r0, c7, c10, 1 ) @ clean D line
add r0, r0, #CACHE_LINE_SIZE
+2:
cmp r0, r1
blo 1b
#endif
mov r0, #0
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
+#ifndef CONFIG_ARM_ERRATA_411920
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
#else
+ b v6_icache_inval_all
+#endif
+#else
mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB
#endif
mov pc, lr
/*
+ * Fault handling for the cache operation above. If the virtual address in r0
+ * isn't mapped, just try the next page.
+ */
+9001:
+ mov r0, r0, lsr #12
+ mov r0, r0, lsl #12
+ add r0, r0, #4096
+ b 2b
+ UNWIND(.fnend )
+ENDPROC(v6_coherent_user_range)
+ENDPROC(v6_coherent_kern_range)
+
+/*
* v6_flush_kern_dcache_page(kaddr)
*
* Ensure that the data held in the page kaddr is written back
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index be93ff02a98d..4b733d14076a 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -13,6 +13,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/unwind.h>
#include "proc-macros.S"
@@ -21,7 +22,7 @@
*
* Flush the whole D-cache.
*
- * Corrupted registers: r0-r5, r7, r9-r11
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
*
* - mm - mm_struct describing address space
*/
@@ -51,8 +52,12 @@ loop1:
loop2:
mov r9, r4 @ create working copy of max way size
loop3:
- orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
- orr r11, r11, r7, lsl r2 @ factor index number into r11
+ ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
+ THUMB( lsl r6, r9, r5 )
+ THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
+ ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11
+ THUMB( lsl r6, r7, r2 )
+ THUMB( orr r11, r11, r6 ) @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge loop3
@@ -82,11 +87,13 @@ ENDPROC(v7_flush_dcache_all)
*
*/
ENTRY(v7_flush_kern_cache_all)
- stmfd sp!, {r4-r5, r7, r9-r11, lr}
+ ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
bl v7_flush_dcache_all
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
- ldmfd sp!, {r4-r5, r7, r9-r11, lr}
+ ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
mov pc, lr
ENDPROC(v7_flush_kern_cache_all)
@@ -147,13 +154,16 @@ ENTRY(v7_coherent_kern_range)
* - the Icache does not read data from the write buffer
*/
ENTRY(v7_coherent_user_range)
+ UNWIND(.fnstart )
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
-1: mcr p15, 0, r0, c7, c11, 1 @ clean D line to the point of unification
+1:
+ USER( mcr p15, 0, r0, c7, c11, 1 ) @ clean D line to the point of unification
dsb
- mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
+ USER( mcr p15, 0, r0, c7, c5, 1 ) @ invalidate I line
add r0, r0, r2
+2:
cmp r0, r1
blo 1b
mov r0, #0
@@ -161,6 +171,17 @@ ENTRY(v7_coherent_user_range)
dsb
isb
mov pc, lr
+
+/*
+ * Fault handling for the cache operation above. If the virtual address in r0
+ * isn't mapped, just try the next page.
+ */
+9001:
+ mov r0, r0, lsr #12
+ mov r0, r0, lsl #12
+ add r0, r0, #4096
+ b 2b
+ UNWIND(.fnend )
ENDPROC(v7_coherent_kern_range)
ENDPROC(v7_coherent_user_range)
@@ -199,10 +220,12 @@ ENTRY(v7_dma_inv_range)
sub r3, r2, #1
tst r0, r3
bic r0, r0, r3
+ it ne
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
tst r1, r3
bic r1, r1, r3
+ it ne
mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D / U line
1:
mcr p15, 0, r0, c7, c6, 1 @ invalidate D / U line
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index fc84fcc74380..661de18634fd 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -10,12 +10,17 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
static DEFINE_SPINLOCK(cpu_asid_lock);
unsigned int cpu_last_asid = ASID_FIRST_VERSION;
+#ifdef CONFIG_SMP
+DEFINE_PER_CPU(struct mm_struct *, current_mm);
+#endif
/*
* We fork()ed a process, and we need a new context for the child
@@ -26,13 +31,105 @@ unsigned int cpu_last_asid = ASID_FIRST_VERSION;
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.id = 0;
+ spin_lock_init(&mm->context.id_lock);
}
+static void flush_context(void)
+{
+ /* set the reserved ASID before flushing the TLB */
+ asm("mcr p15, 0, %0, c13, c0, 1\n" : : "r" (0));
+ isb();
+ local_flush_tlb_all();
+ if (icache_is_vivt_asid_tagged()) {
+ __flush_icache_all();
+ dsb();
+ }
+}
+
+#ifdef CONFIG_SMP
+
+static void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+ /*
+ * Locking needed for multi-threaded applications where the
+ * same mm->context.id could be set from different CPUs during
+ * the broadcast.
+ */
+ spin_lock(&mm->context.id_lock);
+ if (likely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) {
+ /*
+ * Old version of ASID found. Set the new one and
+ * reset mm->cpu_vm_mask.
+ */
+ mm->context.id = asid;
+ cpus_clear(mm->cpu_vm_mask);
+ }
+ spin_unlock(&mm->context.id_lock);
+
+ /*
+ * Set the cpu_vm_mask bit for the current CPU.
+ */
+ cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+}
+
+/*
+ * Reset the ASID on the current CPU. This function call is broadcast
+ * from the CPU handling the ASID rollover and holding cpu_asid_lock.
+ */
+static void reset_context(void *info)
+{
+ unsigned int asid;
+ unsigned int cpu = smp_processor_id();
+ struct mm_struct *mm = per_cpu(current_mm, cpu);
+
+ /*
+ * Check if a current_mm was set on this CPU as it might still
+ * be in the early booting stages and using the reserved ASID.
+ */
+ if (!mm)
+ return;
+
+ smp_rmb();
+ asid = cpu_last_asid + cpu + 1;
+
+ flush_context();
+ set_mm_context(mm, asid);
+
+ /* set the new ASID */
+ asm("mcr p15, 0, %0, c13, c0, 1\n" : : "r" (mm->context.id));
+}
+
+#else
+
+static inline void set_mm_context(struct mm_struct *mm, unsigned int asid)
+{
+ mm->context.id = asid;
+ mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
+}
+
+#endif
+
void __new_context(struct mm_struct *mm)
{
unsigned int asid;
spin_lock(&cpu_asid_lock);
+#ifdef CONFIG_SMP
+ /*
+ * Check the ASID again, in case the change was broadcast from
+ * another CPU before we acquired the lock.
+ */
+ if (unlikely(((mm->context.id ^ cpu_last_asid) >> ASID_BITS) == 0)) {
+ cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+ spin_unlock(&cpu_asid_lock);
+ return;
+ }
+#endif
+ /*
+ * At this point, it is guaranteed that the current mm (with
+ * an old ASID) isn't active on any other CPU since the ASIDs
+ * are changed simultaneously via IPI.
+ */
asid = ++cpu_last_asid;
if (asid == 0)
asid = cpu_last_asid = ASID_FIRST_VERSION;
@@ -42,23 +139,15 @@ void __new_context(struct mm_struct *mm)
* to start a new version and flush the TLB.
*/
if (unlikely((asid & ~ASID_MASK) == 0)) {
- asid = ++cpu_last_asid;
- /* set the reserved ASID before flushing the TLB */
- asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
- :
- : "r" (0));
- isb();
- flush_tlb_all();
- if (icache_is_vivt_asid_tagged()) {
- asm("mcr p15, 0, %0, c7, c5, 0 @ invalidate I-cache\n"
- "mcr p15, 0, %0, c7, c5, 6 @ flush BTAC/BTB\n"
- :
- : "r" (0));
- dsb();
- }
+ asid = cpu_last_asid + smp_processor_id() + 1;
+ flush_context();
+#ifdef CONFIG_SMP
+ smp_wmb();
+ smp_call_function(reset_context, NULL, 1);
+#endif
+ cpu_last_asid += NR_CPUS;
}
- spin_unlock(&cpu_asid_lock);
- mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
- mm->context.id = asid;
+ set_mm_context(mm, asid);
+ spin_unlock(&cpu_asid_lock);
}
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 4127a7bddfe5..ed5c6a68fbd9 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -43,6 +43,7 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to,
copy_page(kto, kfrom);
kunmap_atomic(kto, KM_USER1);
kunmap_atomic(kfrom, KM_USER0);
+ __cpuc_flush_dcache_page(kto);
}
/*
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index f1ef5613ccd4..e37782419831 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -35,7 +35,13 @@
#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+#ifdef CONFIG_MMU
+#define arch_is_nommu() 0
+#else
+#define arch_is_nommu() 1
+#endif
+#ifdef CONFIG_MMU
/*
* These are the page tables (2MB each) covering uncached, DMA consistent allocations
*/
@@ -67,8 +73,7 @@ static DEFINE_SPINLOCK(consistent_lock);
* .vm_end = VMALLOC_END,
* };
*
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.) I would imagine that get_vm_area()
+ * However, vmalloc_head.vm_start is variable (typically, it is depen* the amount of RAM found at boot time.) I would imagine that get_vm_area()
* would have to initialise this each time prior to calling vm_region_alloc().
*/
struct arm_vm_region {
@@ -139,6 +144,7 @@ static struct arm_vm_region *arm_vm_region_find(struct arm_vm_region *head, unsi
out:
return c;
}
+#endif /* CONFIG_MMU */
#ifdef CONFIG_HUGETLB_PAGE
#error ARM Coherent DMA allocator does not (yet) support huge TLB
@@ -148,6 +154,7 @@ static void *
__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
pgprot_t prot)
{
+#ifdef CONFIG_MMU
struct page *page;
struct arm_vm_region *c;
unsigned long order;
@@ -207,7 +214,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
{
void *ptr = page_address(page);
memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
+ smp_dma_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
}
@@ -264,6 +271,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
__free_pages(page, order);
no_page:
*handle = ~0;
+#endif /* CONFIG_MMU */
return NULL;
}
@@ -279,7 +287,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gf
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
- if (arch_is_coherent()) {
+ if (arch_is_coherent() || arch_is_nommu()) {
void *virt;
virt = kmalloc(size, gfp);
@@ -302,6 +310,9 @@ EXPORT_SYMBOL(dma_alloc_coherent);
void *
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
+ if (arch_is_nommu())
+ return dma_alloc_coherent(dev, size, handle, gfp);
+
return __dma_alloc(dev, size, handle, gfp,
pgprot_writecombine(pgprot_kernel));
}
@@ -310,6 +321,8 @@ EXPORT_SYMBOL(dma_alloc_writecombine);
static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
+ int ret = -ENXIO;
+#ifdef CONFIG_MMU
unsigned long flags, user_size, kern_size;
struct arm_vm_region *c;
int ret = -ENXIO;
@@ -333,6 +346,7 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
vma->vm_page_prot);
}
}
+#endif /* CONFIG_MMU */
return ret;
}
@@ -359,22 +373,25 @@ EXPORT_SYMBOL(dma_mmap_writecombine);
*/
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{
+#ifdef CONFIG_MMU
struct arm_vm_region *c;
unsigned long flags, addr;
pte_t *ptep;
int idx;
u32 off;
+#endif
WARN_ON(irqs_disabled());
if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
return;
- if (arch_is_coherent()) {
+ if (arch_is_coherent() || arch_is_nommu()) {
kfree(cpu_addr);
return;
}
+#ifdef CONFIG_MMU
size = PAGE_ALIGN(size);
spin_lock_irqsave(&consistent_lock, flags);
@@ -442,6 +459,7 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
__func__, cpu_addr);
dump_stack();
+#endif /* CONFIG_MMU */
}
EXPORT_SYMBOL(dma_free_coherent);
@@ -450,10 +468,12 @@ EXPORT_SYMBOL(dma_free_coherent);
*/
static int __init consistent_init(void)
{
+ int ret = 0;
+#ifdef CONFIG_MMU
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
- int ret = 0, i = 0;
+ int i = 0;
u32 base = CONSISTENT_BASE;
do {
@@ -476,6 +496,7 @@ static int __init consistent_init(void)
consistent_pte[i++] = pte;
base += (1 << PGDIR_SHIFT);
} while (base < CONSISTENT_END);
+#endif /* !CONFIG_MMU */
return ret;
}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index bc0099d5ae85..d0d17b6a3703 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -153,14 +153,11 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
page = pfn_to_page(pfn);
mapping = page_mapping(page);
- if (mapping) {
#ifndef CONFIG_SMP
- int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
-
- if (dirty)
- __flush_dcache_page(mapping, page);
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+ __flush_dcache_page(mapping, page);
#endif
-
+ if (mapping) {
if (cache_is_vivt())
make_coherent(mapping, vma, addr, pfn);
else if (vma->vm_flags & VM_EXEC)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 0455557a2899..91b0dbba6cfe 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -23,6 +23,7 @@
#include "fault.h"
+#ifdef CONFIG_MMU
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
@@ -97,6 +98,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
printk("\n");
}
+#else /* CONFIG_MMU */
+void show_pte(struct mm_struct *mm, unsigned long addr)
+{ }
+#endif /* CONFIG_MMU */
/*
* Oops. The kernel tried to access some page that wasn't present.
@@ -171,6 +176,7 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
__do_kernel_fault(mm, addr, fsr, regs);
}
+#ifdef CONFIG_MMU
#define VM_FAULT_BADMAP 0x010000
#define VM_FAULT_BADACCESS 0x020000
@@ -322,6 +328,13 @@ no_context:
__do_kernel_fault(mm, addr, fsr, regs);
return 0;
}
+#else /* CONFIG_MMU */
+static int
+do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+ return 0;
+}
+#endif /* CONFIG_MMU */
/*
* First Level Translation Fault Handler
@@ -340,6 +353,7 @@ no_context:
* interrupt or a critical region, and should only copy the information
* from the master page table, nothing more.
*/
+#ifdef CONFIG_MMU
static int __kprobes
do_translation_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
@@ -378,6 +392,14 @@ bad_area:
do_bad_area(addr, fsr, regs);
return 0;
}
+#else /* CONFIG_MMU */
+static int
+do_translation_fault(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+{
+ return 0;
+}
+#endif /* CONFIG_MMU */
/*
* Some section permission faults need to be handled gracefully.
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 0fa9bf388f0b..03e37fa1c294 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -32,10 +32,14 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
asm( "mcrr p15, 0, %1, %0, c14\n"
" mcr p15, 0, %2, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
" mcr p15, 0, %2, c7, c5, 0\n"
+#else
+ " bl v6_icache_inval_all\n"
+#endif
:
: "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
- : "cc");
+ : "r0", "r1", "lr");
}
void flush_cache_mm(struct mm_struct *mm)
@@ -48,11 +52,15 @@ void flush_cache_mm(struct mm_struct *mm)
if (cache_is_vipt_aliasing()) {
asm( "mcr p15, 0, %0, c7, c14, 0\n"
+ " mcr p15, 0, %0, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
" mcr p15, 0, %0, c7, c5, 0\n"
- " mcr p15, 0, %0, c7, c10, 4"
+#else
+ " bl v6_icache_inval_all\n"
+#endif
:
: "r" (0)
- : "cc");
+ : "r0", "r1", "lr", "cc");
}
}
@@ -67,11 +75,15 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
if (cache_is_vipt_aliasing()) {
asm( "mcr p15, 0, %0, c7, c14, 0\n"
+ " mcr p15, 0, %0, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
" mcr p15, 0, %0, c7, c5, 0\n"
- " mcr p15, 0, %0, c7, c10, 4"
+#else
+ " bl v6_icache_inval_all\n"
+#endif
:
: "r" (0)
- : "cc");
+ : "r0", "r1", "lr", "cc");
}
}
@@ -107,8 +119,7 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
}
/* VIPT non-aliasing cache */
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask) &&
- vma->vm_flags & VM_EXEC) {
+ if (vma->vm_flags & VM_EXEC) {
unsigned long addr = (unsigned long)kaddr;
/* only flushing the kernel mapping on non-aliasing VIPT */
__cpuc_coherent_kern_range(addr, addr + len);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 80fd3b69ae1f..30e684309139 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -422,7 +422,7 @@ free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
/*
* Convert start_pfn/end_pfn to a struct page pointer.
*/
- start_pg = pfn_to_page(start_pfn);
+ start_pg = pfn_to_page(start_pfn - 1) + 1;
end_pg = pfn_to_page(end_pfn);
/*
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index ad7bacc693b2..b62c6a5b8619 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -12,6 +12,7 @@
#include <asm/cacheflush.h>
#include <asm/sections.h>
#include <asm/page.h>
+#include <asm/setup.h>
#include <asm/mach/arch.h>
#include "mm.h"
@@ -33,6 +34,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
BOOTMEM_DEFAULT);
#endif
+#ifndef CONFIG_CPU_V7M
/*
* Register the exception vector page.
* some architectures which the DRAM is the exception vector to trap,
@@ -40,6 +42,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
*/
reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE,
BOOTMEM_DEFAULT);
+#endif
}
/*
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 54b1f721dec8..f1559c227784 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -77,6 +77,7 @@
* Sanity check the PTE configuration for the code below - which makes
* certain assumptions about how these bits are layed out.
*/
+#ifdef CONFIG_MMU
#if L_PTE_SHARED != PTE_EXT_SHARED
#error PTE shared bit mismatch
#endif
@@ -90,6 +91,7 @@
L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED
#error Invalid Linux PTE bit settings
#endif
+#endif /* CONFIG_MMU */
/*
* The ARMv6 and ARMv7 set_pte_ext translation function.
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index f0cc599facb7..7959567970c7 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -169,9 +169,28 @@ __v6_setup:
#endif /* CONFIG_MMU */
adr r5, v6_crval
ldmia r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ orr r6, r6, #1 << 25 @ big-endian page tables
+#endif
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, r5 @ clear bits them
orr r0, r0, r6 @ set them
+#ifdef CONFIG_ARM_ERRATA_364296
+ /* Workaround for the 364296 ARM1136 r0pX errata (possible cache data
+ * corruption with hit-under-miss enabled). The conditional code below
+ * (setting the undocumented bit 31 in the auxiliary control register
+ * and the FI bit in the control register) disables hit-under-miss
+ * without putting the processor into full low interrupt latency mode.
+ */
+ ldr r6, =0x4107b360 @ id for ARM1136 r0pX
+ mrc p15, 0, r5, c0, c0, 0 @ get processor id
+ bic r5, r5, #0xf @ mask out part bits [3:0]
+ teq r5, r6 @ check for the faulty core
+ mrceq p15, 0, r5, c1, c0, 1 @ load aux control reg
+ orreq r5, r5, #(1 << 31) @ set the undocumented bit 31
+ mcreq p15, 0, r5, c1, c0, 1 @ write aux control reg
+ orreq r0, r0, #(1 << 21) @ low interrupt latency configuration
+#endif
mov pc, lr @ return to head.S:__ret
/*
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index d1ebec42521d..fd90b1b55e13 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -18,12 +18,24 @@
#include "proc-macros.S"
-#define TTB_C (1 << 0)
#define TTB_S (1 << 1)
#define TTB_RGN_NC (0 << 3)
#define TTB_RGN_OC_WBWA (1 << 3)
#define TTB_RGN_OC_WT (2 << 3)
#define TTB_RGN_OC_WB (3 << 3)
+#define TTB_NOS (1 << 5)
+#define TTB_IRGN_NC ((0 << 0) | (0 << 6))
+#define TTB_IRGN_WBWA ((0 << 0) | (1 << 6))
+#define TTB_IRGN_WT ((1 << 0) | (0 << 6))
+#define TTB_IRGN_WB ((1 << 0) | (1 << 6))
+
+#ifndef CONFIG_SMP
+/* PTWs cacheable, inner WB not shareable, outer WB not shareable */
+#define TTB_FLAGS TTB_IRGN_WB|TTB_RGN_OC_WB
+#else
+/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
+#define TTB_FLAGS TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
+#endif
#ifndef CONFIG_SMP
#define TTB_FLAGS TTB_C|TTB_RGN_OC_WB @ mark PTWs cacheable, outer WB
@@ -95,6 +107,9 @@ ENTRY(cpu_v7_switch_mm)
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
orr r0, r0, #TTB_FLAGS
+#ifdef CONFIG_ARM_ERRATA_430973
+ mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
+#endif
mcr p15, 0, r2, c13, c0, 1 @ set reserved context ID
isb
1: mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
@@ -117,7 +132,9 @@ ENDPROC(cpu_v7_switch_mm)
*/
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
- str r1, [r0], #-2048 @ linux version
+ ARM( str r1, [r0], #-2048 ) @ linux version
+ THUMB( str r1, [r0] ) @ linux version
+ THUMB( sub r0, r0, #2048 )
bic r3, r1, #0x000003f0
bic r3, r3, #PTE_TYPE_MASK
@@ -125,21 +142,26 @@ ENTRY(cpu_v7_set_pte_ext)
orr r3, r3, #PTE_EXT_AP0 | 2
tst r1, #1 << 4
+ it ne
orrne r3, r3, #PTE_EXT_TEX(1)
tst r1, #L_PTE_WRITE
+ ite ne
tstne r1, #L_PTE_DIRTY
orreq r3, r3, #PTE_EXT_APX
tst r1, #L_PTE_USER
+ ittt ne
orrne r3, r3, #PTE_EXT_AP1
tstne r3, #PTE_EXT_APX
bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
tst r1, #L_PTE_EXEC
+ it eq
orreq r3, r3, #PTE_EXT_XN
tst r1, #L_PTE_YOUNG
+ ite ne
tstne r1, #L_PTE_PRESENT
moveq r3, #0
@@ -173,13 +195,31 @@ cpu_v7_name:
__v7_setup:
#ifdef CONFIG_SMP
mrc p15, 0, r0, c1, c0, 1 @ Enable SMP/nAMP mode
- orr r0, r0, #(0x1 << 6)
- mcr p15, 0, r0, c1, c0, 1
+ tst r0, #(0x1 << 6) @ already enabled?
+ itt eq
+ orreq r0, r0, #(1 << 6) | (1 << 0)
+ mcreq p15, 0, r0, c1, c0, 1
#endif
adr r12, __v7_setup_stack @ the local stack
stmia r12, {r0-r5, r7, r9, r11, lr}
bl v7_flush_dcache_all
ldmia r12, {r0-r5, r7, r9, r11, lr}
+#ifdef CONFIG_ARM_ERRATA_430973
+ mrc p15, 0, r10, c1, c0, 1 @ read aux control register
+ orr r10, r10, #(1 << 6) @ set IBE to 1
+ mcr p15, 0, r10, c1, c0, 1 @ write aux control register
+#endif
+#ifdef CONFIG_ARM_ERRATA_458693
+ mrc p15, 0, r10, c1, c0, 1 @ read aux control register
+ orr r10, r10, #(1 << 5) @ set L1NEON to 1
+ orr r10, r10, #(1 << 9) @ set PLDNOP to 1
+ mcr p15, 0, r10, c1, c0, 1 @ write aux control register
+#endif
+#ifdef CONFIG_ARM_ERRATA_460075
+ mrc p15, 1, r10, c9, c0, 2 @ read L2 cache aux ctrl register
+ orr r10, r10, #(1 << 22) @ set the Write Allocate disable bit
+ mcr p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register
+#endif
mov r10, #0
#ifdef HARVARD_CACHE
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
@@ -192,13 +232,16 @@ __v7_setup:
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
mov r10, #0x1f @ domains 0, 1 = manager
mcr p15, 0, r10, c3, c0, 0 @ load domain access register
-#endif
ldr r5, =0xff0aa1a8
ldr r6, =0x40e040e0
mcr p15, 0, r5, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
+#endif
adr r5, v7_crval
ldmia r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+ orr r6, r6, #1 << 25 @ big-endian page tables
+#endif
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, r5 @ clear bits them
orr r0, r0, r6 @ set them
@@ -206,14 +249,15 @@ __v7_setup:
ENDPROC(__v7_setup)
/* AT
- * TFR EV X F I D LR
- * .EEE ..EE PUI. .T.T 4RVI ZFRS BLDP WCAM
+ * TFR EV X F I D LR S
+ * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
* rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
- * 1 0 110 0011 1.00 .111 1101 < we want
+ * 1 0 110 0011 1100 .111 1101 < we want
*/
.type v7_crval, #object
v7_crval:
- crval clear=0x0120c302, mmuset=0x10c0387d, ucset=0x00c0187c
+ ARM( crval clear=0x0120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c )
+ THUMB( crval clear=0x0120c302, mmuset=0x50c03c7d, ucset=0x40c01c7c )
__v7_setup_stack:
.space 4 * 11 @ 11 registers
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
new file mode 100644
index 000000000000..ff97c011ae60
--- /dev/null
+++ b/arch/arm/mm/proc-v7m.S
@@ -0,0 +1,184 @@
+/*
+ * linux/arch/arm/mm/proc-v7m.S
+ *
+ * Copyright (C) 2008 ARM Ltd.
+ * Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This is the "shell" of the ARMv7-M processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(cpu_v7m_proc_init)
+ mov pc, lr
+ENDPROC(cpu_v7m_proc_init)
+
+ENTRY(cpu_v7m_proc_fin)
+ mov pc, lr
+ENDPROC(cpu_v7m_proc_fin)
+
+/*
+ * cpu_v7m_reset(loc)
+ *
+ * Perform a soft reset of the system. Put the CPU into the
+ * same state as it would be if it had been reset, and branch
+ * to what would be the reset vector.
+ *
+ * - loc - location to jump to for soft reset
+ *
+ * It is assumed that:
+ */
+ .align 5
+ENTRY(cpu_v7m_reset)
+ mov pc, r0
+ENDPROC(cpu_v7m_reset)
+
+/*
+ * cpu_v7m_do_idle()
+ *
+ * Idle the processor (eg, wait for interrupt).
+ *
+ * IRQs are already disabled.
+ */
+ENTRY(cpu_v7m_do_idle)
+ wfi
+ mov pc, lr
+ENDPROC(cpu_v7m_do_idle)
+
+ENTRY(cpu_v7m_dcache_clean_area)
+ mov pc, lr
+ENDPROC(cpu_v7m_dcache_clean_area)
+
+/*
+ * cpu_v7m_switch_mm(pgd_phys, tsk)
+ *
+ * Set the translation table base pointer to be pgd_phys
+ *
+ * - pgd_phys - physical address of new TTB
+ *
+ * It is assumed that:
+ * - we are not using split page tables
+ */
+ENTRY(cpu_v7m_switch_mm)
+ mov pc, lr
+ENDPROC(cpu_v7m_switch_mm)
+
+ENTRY(cpu_v7m_set_pte_ext)
+ mov pc, lr
+ENDPROC(cpu_v7m_set_pte_ext)
+
+cpu_v7m_name:
+ .ascii "ARMv7-M Processor"
+ .align
+
+ .section ".text.init", #alloc, #execinstr
+
+/*
+ * __v7m_setup
+ *
+ * Initialise TLB, Caches, and MMU state ready to switch the MMU
+ * on. Return in r0 the new CP15 C1 control register setting.
+ *
+ * We automatically detect if we have a Harvard cache, and use the
+ * Harvard cache control instructions insead of the unified cache
+ * control instructions.
+ *
+ * This should be able to cover all ARMv7-M cores.
+ *
+ * It is assumed that:
+ * - cache type register is implemented
+ */
+__v7m_setup:
+ @ Configure the vector table base address
+ ldr r0, =0xe000ed08 @ vector table base address
+ ldr r12, =vector_table
+ str r12, [r0]
+
+ @ Lower the priority of the SVC and PendSV exceptions
+ ldr r0, =0xe000ed1c
+ mov r5, #0x80000000
+ str r5, [r0] @ set SVC priority
+ ldr r0, =0xe000ed20
+ mov r5, #0x00800000
+ str r5, [r0] @ set PendSV priority
+
+ @ SVC to run the kernel in this mode
+ adr r0, BSYM(1f)
+ ldr r5, [r12, #11 * 4] @ read the SVC vector entry
+ str r0, [r12, #11 * 4] @ write the temporary SVC vector entry
+ mov r6, lr @ save LR
+ mov r7, sp @ save SP
+ ldr sp, =__v7m_setup_stack_top
+ cpsie i
+ svc #0
+1: cpsid i
+ str r5, [r12, #11 * 4] @ restore the original SVC vector entry
+ mov lr, r6 @ restore LR
+ mov sp, r7 @ restore SP
+
+ @ Special-purpose control register
+ mov r0, #1
+ msr control, r0 @ Thread mode has unpriviledged access
+
+ @ Configure the System Control Register
+ ldr r0, =0xe000ed14 @ system control register
+ ldr r12, [r0]
+ orr r12, #1 << 9 @ STKALIGN
+ str r12, [r0]
+ mov pc, lr
+ENDPROC(__v7m_setup)
+
+ .align 2
+ .type v7m_processor_functions, #object
+ENTRY(v7m_processor_functions)
+ .word v7m_early_abort
+ .word cpu_v7m_proc_init
+ .word cpu_v7m_proc_fin
+ .word cpu_v7m_reset
+ .word cpu_v7m_do_idle
+ .word cpu_v7m_dcache_clean_area
+ .word cpu_v7m_switch_mm
+ .word cpu_v7m_set_pte_ext
+ .word pabort_noifar
+ .size v7m_processor_functions, . - v7m_processor_functions
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv7m"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v7m"
+ .size cpu_elf_name, . - cpu_elf_name
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+
+ /*
+ * Match any ARMv7-M processor core.
+ */
+ .type __v7m_proc_info, #object
+__v7m_proc_info:
+ .long 0x000f0000 @ Required ID value
+ .long 0x000f0000 @ Mask for ID
+ .long 0 @ proc_info_list.__cpu_mm_mmu_flags
+ .long 0 @ proc_info_list.__cpu_io_mmu_flags
+ b __v7m_setup @ proc_info_list.__cpu_flush
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+ .long cpu_v7m_name
+ .long v7m_processor_functions @ proc_info_list.proc
+ .long 0 @ proc_info_list.tlb
+ .long 0 @ proc_info_list.user
+ .long 0 @ proc_info_list.cache
+ .size __v7m_proc_info, . - __v7m_proc_info
+
+__v7m_setup_stack:
+ .space 4 * 8 @ 8 registers
+__v7m_setup_stack_top:
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index 24ba5109f2e7..010c4781615a 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -41,9 +41,11 @@ ENTRY(v7wbi_flush_user_tlb_range)
mov r1, r1, lsl #PAGE_SHIFT
vma_vm_flags r2, r2 @ get vma->vm_flags
1:
- mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA (was 1)
- tst r2, #VM_EXEC @ Executable area ?
- mcrne p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA (was 1)
+#ifdef CONFIG_SMP
+ mcr p15, 0, r0, c8, c3, 1 @ TLB invalidate U MVA (shareable)
+#else
+ mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate U MVA
+#endif
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
@@ -68,8 +70,11 @@ ENTRY(v7wbi_flush_kern_tlb_range)
mov r0, r0, lsl #PAGE_SHIFT
mov r1, r1, lsl #PAGE_SHIFT
1:
- mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA
- mcr p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA
+#ifdef CONFIG_SMP
+ mcr p15, 0, r0, c8, c3, 1 @ TLB invalidate U MVA (shareable)
+#else
+ mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate U MVA
+#endif
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
@@ -86,5 +91,5 @@ ENDPROC(v7wbi_flush_kern_tlb_range)
ENTRY(v7wbi_tlb_fns)
.long v7wbi_flush_user_tlb_range
.long v7wbi_flush_kern_tlb_range
- .long v6wbi_tlb_flags
+ .long v7wbi_tlb_flags
.size v7wbi_tlb_fns, . - v7wbi_tlb_fns
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index 88e31f549f50..1593e3753549 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -6,9 +6,7 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o \
timer_int.o )
-oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
+oprofile-y := $(DRIVER_OBJS) common.o backtrace.o op_arm11.o op_v7.o op_model_v6-7.o
+oprofile-$(CONFIG_CACHE_L2X0) += op_l2x0.o
+oprofile-$(CONFIG_SMP) += op_scu.o
oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o
-oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o
-oprofile-$(CONFIG_OPROFILE_ARMV6) += op_model_v6.o
-oprofile-$(CONFIG_OPROFILE_MPCORE) += op_model_mpcore.o
-oprofile-$(CONFIG_OPROFILE_ARMV7) += op_model_v7.o
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
index cefc21c2eee4..d805a52b5032 100644
--- a/arch/arm/oprofile/backtrace.c
+++ b/arch/arm/oprofile/backtrace.c
@@ -18,15 +18,14 @@
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
-
-#include "../kernel/stacktrace.h"
+#include <asm/stacktrace.h>
static int report_trace(struct stackframe *frame, void *d)
{
unsigned int *depth = d;
if (*depth) {
- oprofile_add_trace(frame->lr);
+ oprofile_add_trace(frame->pc);
(*depth)--;
}
@@ -70,9 +69,12 @@ void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
if (!user_mode(regs)) {
- unsigned long base = ((unsigned long)regs) & ~(THREAD_SIZE - 1);
- walk_stackframe(regs->ARM_fp, base, base + THREAD_SIZE,
- report_trace, &depth);
+ struct stackframe frame;
+ frame.fp = regs->ARM_fp;
+ frame.sp = regs->ARM_sp;
+ frame.lr = regs->ARM_lr;
+ frame.pc = regs->ARM_pc;
+ walk_stackframe(&frame, report_trace, &depth);
return;
}
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 3fcd752d6146..2680f4d4b2f3 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -14,6 +14,10 @@
#include <linux/sysdev.h>
#include <linux/mutex.h>
+#include <asm/system.h>
+#include <asm/cputype.h>
+#include <asm/io.h>
+
#include "op_counter.h"
#include "op_arm_model.h"
@@ -130,24 +134,37 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
{
struct op_arm_model_spec *spec = NULL;
int ret = -ENODEV;
+ int cpu_arch = cpu_architecture();
ops->backtrace = arm_backtrace;
-#ifdef CONFIG_CPU_XSCALE
+ if (cpu_is_xscale())
spec = &op_xscale_spec;
-#endif
-
-#ifdef CONFIG_OPROFILE_ARMV6
+ else if (cpu_is_11mpcore() || cpu_arch == CPU_ARCH_ARMv6) {
+ /* cpu_architecture returns V7 for MPCore! */
spec = &op_armv6_spec;
-#endif
-
-#ifdef CONFIG_OPROFILE_MPCORE
- spec = &op_mpcore_spec;
-#endif
-
-#ifdef CONFIG_OPROFILE_ARMV7
+ if (cpu_is_11mpcore())
+ spec->name = "arm/11mpcore";
+ }
+ else if (cpu_arch == CPU_ARCH_ARMv7) {
spec = &op_armv7_spec;
-#endif
+ /*
+ * V7 CPUs all have the same kind of PMUs, but have a variable
+ * number of them. So the kernel side of Oprofile only needs
+ * to know whether we have the L2x0, and whether we're SMP.
+ * The user side needs more information, to decide which
+ * events file to use because, for example, some A8 event
+ * numbers differ from A9 event numbers).
+ */
+ if (cpu_is_a9()) {
+ if (is_smp())
+ spec->name = "arm/a9mpcore";
+ else
+ spec->name = "arm/a9";
+ }
+ else
+ spec->name = "arm/a8";
+ }
if (spec) {
ret = spec->init();
@@ -167,7 +184,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
ops->start = op_arm_start;
ops->stop = op_arm_stop;
ops->cpu_type = op_arm_model->name;
- printk(KERN_INFO "oprofile: using %s\n", spec->name);
+ printk(KERN_INFO "oprofile: cpu_architecture() returns 0x%x, using %s model\n", cpu_arch, spec->name);
}
return ret;
diff --git a/arch/arm/oprofile/op_arm11.c b/arch/arm/oprofile/op_arm11.c
new file mode 100644
index 000000000000..4daa0084df15
--- /dev/null
+++ b/arch/arm/oprofile/op_arm11.c
@@ -0,0 +1,164 @@
+/**
+ * @file op_arm11.c
+ * ARM11 CP15 Performance Monitor Unit Driver
+ *
+ * @remark Copyright 2004-7 ARM SMP Development Team
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_arm11.h"
+
+static inline void arm11_write_pmnc(u32 val)
+{
+ /* upper 4bits and 7, 11 are write-as-0 */
+ val &= 0x0ffff77f;
+ asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
+}
+
+static inline u32 arm11_read_pmnc(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
+ return val;
+}
+
+static void arm11_reset_counter(unsigned int cnt)
+{
+ u32 val = -(u32)counter_config[COUNTER_CPUn_PMNm(smp_processor_id(), cnt)].count;
+ switch (cnt) {
+ case CCNT:
+ asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
+ break;
+
+ case PMN0:
+ asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
+ break;
+
+ case PMN1:
+ asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
+ break;
+ }
+}
+
+int arm11_setup_pmu(void)
+{
+ unsigned long event;
+ unsigned cpu;
+ u32 pmnc;
+
+ cpu = smp_processor_id();
+ if (arm11_read_pmnc() & PMCR_E) {
+ printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", cpu);
+ return -EBUSY;
+ }
+
+ /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
+ arm11_write_pmnc(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
+ PMCR_C | PMCR_P);
+
+ pmnc = 0;
+
+ if (counter_config[COUNTER_CPUn_PMNm(cpu, PMN0)].enabled) {
+ event = counter_config[COUNTER_CPUn_PMNm(cpu, PMN0)].event & 255;
+ pmnc |= event << 20;
+ pmnc |= PMCR_IEN_PMN0;
+ arm11_reset_counter(PMN0);
+ }
+ if (counter_config[COUNTER_CPUn_PMNm(cpu, PMN1)].enabled) {
+ event = counter_config[COUNTER_CPUn_PMNm(cpu, PMN1)].event & 255;
+ pmnc |= event << 12;
+ pmnc |= PMCR_IEN_PMN1;
+ arm11_reset_counter(PMN1);
+ }
+ if (counter_config[COUNTER_CPUn_CCNT(cpu)].enabled) {
+ pmnc |= PMCR_IEN_CCNT;
+ arm11_reset_counter(CCNT);
+ }
+
+ arm11_write_pmnc(pmnc);
+ return 0;
+}
+
+int arm11_start_pmu(void)
+{
+ arm11_write_pmnc(arm11_read_pmnc() | PMCR_E);
+ return 0;
+}
+
+int arm11_stop_pmu(void)
+{
+ unsigned int cnt;
+
+ arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E);
+
+ for (cnt = PMN0; cnt <= CCNT; cnt++)
+ arm11_reset_counter(cnt);
+
+ return 0;
+}
+
+/*
+ * CPU counters' IRQ handler (one IRQ per CPU)
+ */
+static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
+{
+ struct pt_regs *regs = get_irq_regs();
+ unsigned int cnt;
+ u32 pmnc;
+
+ pmnc = arm11_read_pmnc();
+
+ /* First check if the two event counters have overflowed */
+ for (cnt = PMN0; cnt <= PMN1; ++cnt) {
+ if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) {
+ arm11_reset_counter(cnt);
+ oprofile_add_sample(regs, COUNTER_CPUn_PMNm(smp_processor_id(), cnt));
+ }
+ }
+
+ /* Now check if the cycle counter has overflowed */
+ if ((pmnc & PMCR_OFL_CCNT) && (pmnc & PMCR_IEN_CCNT)) {
+ arm11_reset_counter(CCNT);
+ oprofile_add_sample(regs, COUNTER_CPUn_CCNT(smp_processor_id()));
+ }
+
+ /* Clear counter flag(s) */
+ arm11_write_pmnc(pmnc);
+ return IRQ_HANDLED;
+}
+
+int arm11_request_interrupts(int *irqs, int nr)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for(i = 0; i < nr; i++) {
+ ret = request_irq(irqs[i], arm11_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL);
+ if (ret != 0) {
+ printk(KERN_ERR "oprofile: unable to request IRQ%u for CP15 PMU\n",
+ irqs[i]);
+ break;
+ }
+ }
+
+ if (i != nr)
+ while (i-- != 0)
+ free_irq(irqs[i], NULL);
+
+ return ret;
+}
+
+void arm11_release_interrupts(int *irqs, int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ free_irq(irqs[i], NULL);
+}
diff --git a/arch/arm/oprofile/op_arm11.h b/arch/arm/oprofile/op_arm11.h
new file mode 100644
index 000000000000..6047ec209104
--- /dev/null
+++ b/arch/arm/oprofile/op_arm11.h
@@ -0,0 +1,44 @@
+/**
+ * @file op_arm11.h
+ * ARM11 CP15 Performance Monitor Unit Driver
+ * @remark Copyright 2004-7 ARM SMP Development Team
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 Oprofile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Zwane Mwaikambo
+ */
+#ifndef OP_ARM11_H
+#define OP_ARM11_H
+
+/*
+ * Per-CPU PMCR
+ */
+#define PMCR_E (1 << 0) /* Enable */
+#define PMCR_P (1 << 1) /* Count reset */
+#define PMCR_C (1 << 2) /* Cycle counter reset */
+#define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */
+#define PMCR_IEN_PMN0 (1 << 4) /* Interrupt enable count reg 0 */
+#define PMCR_IEN_PMN1 (1 << 5) /* Interrupt enable count reg 1 */
+#define PMCR_IEN_CCNT (1 << 6) /* Interrupt enable cycle counter */
+#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
+#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
+#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
+
+#define PMN0 0
+#define PMN1 1
+
+#define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter))
+
+int arm11_setup_pmu(void);
+int arm11_start_pmu(void);
+int arm11_stop_pmu(void);
+int arm11_request_interrupts(int *, int);
+void arm11_release_interrupts(int *, int);
+
+#endif
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 8c4e4f6a1de3..05a206eff865 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -20,16 +20,97 @@ struct op_arm_model_spec {
char *name;
};
-#ifdef CONFIG_CPU_XSCALE
extern struct op_arm_model_spec op_xscale_spec;
-#endif
-
extern struct op_arm_model_spec op_armv6_spec;
-extern struct op_arm_model_spec op_mpcore_spec;
extern struct op_arm_model_spec op_armv7_spec;
extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
extern void op_arm_exit(void);
+
+/*
+ * The macros need to be reimplemented as things we can call at runtime,
+ * along with cpu_is_xscale in system.h
+ */
+#ifdef CONFIG_CACHE_L2X0
+#define have_l2x0() 1
+#else
+#define have_l2x0() 0
+#endif
+#ifdef CONFIG_SMP
+#define is_smp() 1
+#else
+#define is_smp() 0
+#endif
+#ifdef CONFIG_REALVIEW_EB_A9MP
+#define cpu_is_a9() 1
+#else
+#define cpu_is_a9() 0
+#endif
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_MACH_REALVIEW_PB11MP)
+#define cpu_is_11mpcore() 1
+#else
+#define cpu_is_11mpcore() 0
+#endif
+#ifdef CONFIG_MACH_REALVIEW_PBX
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/board-pbx.h>
+#undef cpu_is_11mpcore
+#define cpu_is_11mpcore() core_tile_pbx11mp()
+#undef cpu_is_a9
+#define cpu_is_a9() core_tile_pbxa9mp()
+#endif
+
+/*
+ * ARM11MPCore SCU event monitor support
+ */
+#ifdef CONFIG_SMP
+#if defined(CONFIG_MACH_REALVIEW_EB)
+#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10)
+#elif defined(CONFIG_MACH_REALVIEW_PB11MP)
+#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_TC11MP_SCU_BASE + 0x10)
+#elif defined(CONFIG_MACH_REALVIEW_PBX)
+#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_PBX_TILE_SCU_BASE + 0x10)
+#else
+#error Cannot determine the base address of the SCU
+#endif
+#endif
+
+/*
+ * IRQ numbers for PMUs (A9MPCore and 11MPCore) and SCU (11MPCore only)
+ */
+#if defined(CONFIG_MACH_REALVIEW_EB) || defined(CONFIG_MACH_REALVIEW_PB11MP)
+#define IRQ_PMU_CPU0 IRQ_TC11MP_PMU_CPU0
+#define IRQ_PMU_CPU1 IRQ_TC11MP_PMU_CPU1
+#define IRQ_PMU_CPU2 IRQ_TC11MP_PMU_CPU2
+#define IRQ_PMU_CPU3 IRQ_TC11MP_PMU_CPU3
+#define IRQ_PMU_SCU0 IRQ_TC11MP_PMU_SCU0
+#define IRQ_PMU_SCU1 IRQ_TC11MP_PMU_SCU1
+#define IRQ_PMU_SCU2 IRQ_TC11MP_PMU_SCU2
+#define IRQ_PMU_SCU3 IRQ_TC11MP_PMU_SCU3
+#define IRQ_PMU_SCU4 IRQ_TC11MP_PMU_SCU4
+#define IRQ_PMU_SCU5 IRQ_TC11MP_PMU_SCU5
+#define IRQ_PMU_SCU6 IRQ_TC11MP_PMU_SCU6
+#define IRQ_PMU_SCU7 IRQ_TC11MP_PMU_SCU7
+#elif defined(CONFIG_MACH_REALVIEW_PBX)
+#define IRQ_PMU_CPU0 IRQ_PBX_PMU_CPU0
+#define IRQ_PMU_CPU1 IRQ_PBX_PMU_CPU1
+#define IRQ_PMU_CPU2 IRQ_PBX_PMU_CPU2
+#define IRQ_PMU_CPU3 IRQ_PBX_PMU_CPU3
+#define IRQ_PMU_SCU0 IRQ_PBX_PMU_SCU0
+#define IRQ_PMU_SCU1 IRQ_PBX_PMU_SCU1
+#define IRQ_PMU_SCU2 IRQ_PBX_PMU_SCU2
+#define IRQ_PMU_SCU3 IRQ_PBX_PMU_SCU3
+#define IRQ_PMU_SCU4 IRQ_PBX_PMU_SCU4
+#define IRQ_PMU_SCU5 IRQ_PBX_PMU_SCU5
+#define IRQ_PMU_SCU6 IRQ_PBX_PMU_SCU6
+#define IRQ_PMU_SCU7 IRQ_PBX_PMU_SCU7
+#elif defined(CONFIG_ARCH_OMAP2)
+#define IRQ_PMU_CPU0 3
+#else
+#define IRQ_PMU_CPU0 NO_IRQ
+#endif
+
#endif /* OP_ARM_MODEL_H */
diff --git a/arch/arm/oprofile/op_counter.h b/arch/arm/oprofile/op_counter.h
index ca942a63b52f..3d92fb59b0a1 100644
--- a/arch/arm/oprofile/op_counter.h
+++ b/arch/arm/oprofile/op_counter.h
@@ -24,4 +24,31 @@ struct op_counter_config {
extern struct op_counter_config *counter_config;
+
+/*
+ * List of userspace counter numbers: we use the same layout for both
+ * the V6 and V7 oprofile models.
+ * 0- 7 CPU0 event counters and cycle counter
+ * 8-15 CPU1 event counters and cycle counter
+ * 16-23 CPU2 event counters and cycle counter
+ * 24-31 CPU3 event counters and cycle counter
+ * 32-39 SCU counters
+ * 40-41 L2X0 counters
+ */
+
+#define PMU_COUNTERS_PER_CPU 8 /* 7 event counters, 1 cycle counter */
+#define CCNT (PMU_COUNTERS_PER_CPU - 1)
+#define MAX_CPUS 4
+
+#define COUNTER_CPUn_PMNm(N,M) ((N) * PMU_COUNTERS_PER_CPU + (M))
+#define COUNTER_CPUn_CCNT(N) ((N+1) * PMU_COUNTERS_PER_CPU - 1)
+
+#define COUNTER_SCU_MN(N) (PMU_COUNTERS_PER_CPU * MAX_CPUS + (N))
+#define NUM_SCU_COUNTERS 8
+
+#define COUNTER_L2X0_EC(N) (COUNTER_SCU_MN(NUM_SCU_COUNTERS) + (N))
+#define L2X0_NUM_COUNTERS 2
+
+#define NUM_COUNTERS COUNTER_L2X0_EC(L2X0_NUM_COUNTERS)
+
#endif /* OP_COUNTER_H */
diff --git a/arch/arm/oprofile/op_l2x0.c b/arch/arm/oprofile/op_l2x0.c
new file mode 100644
index 000000000000..28b5fa750910
--- /dev/null
+++ b/arch/arm/oprofile/op_l2x0.c
@@ -0,0 +1,244 @@
+/**
+ * @file op_model_l2x0.c
+ * ARM L220/L230 Level 2 Cache Controller Event Counter Driver
+ * @remark Copyright 2004-7 ARM SMP Development Team
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+
+#include <asm/io.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_l2x0.h"
+
+static unsigned l2x0_base, l2x0_irq;
+
+/*
+ * Determine L2X0 base address and event counter IRQ
+ */
+void l2x0_ec_setup(void)
+{
+#if defined(CONFIG_MACH_REALVIEW_EB)
+ l2x0_base = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE);
+ l2x0_irq = IRQ_EB11MP_L220_EVENT;
+#elif defined(CONFIG_MACH_REALVIEW_PB11MP)
+ l2x0_base = IO_ADDRESS(REALVIEW_TC11MP_L220_BASE);
+ l2x0_irq = IRQ_TC11MP_L220_EVENT;
+#elif defined(CONFIG_MACH_REALVIEW_PBX)
+ l2x0_base = IO_ADDRESS(REALVIEW_PBX_TILE_L220_BASE);
+ l2x0_irq = IRQ_PBX_L220_EVENT;
+#else
+#error l2x0_base and l2x0_irq not set!
+#endif
+}
+
+
+
+/*
+ * Read the configuration of an event counter
+ */
+static inline u32 l2x0_ec_read_config(unsigned int cnt)
+{
+ return readl(l2x0_base + L2X0_EVENT_CNT0_CFG - cnt * 4);
+}
+
+/*
+ * Change the configuration of an event counter
+ */
+static inline void l2x0_ec_write_config(unsigned int cnt, u32 config)
+{
+ writel(config, l2x0_base + L2X0_EVENT_CNT0_CFG - cnt * 4);
+}
+
+/*
+ * Reset a counter to its initial value
+ */
+static inline void l2x0_ec_reset(unsigned int cnt)
+{
+ u32 val, temp;
+
+ /*
+ * We can only write to the counter value when the counter is disabled
+ */
+ temp = l2x0_ec_read_config(cnt);
+ l2x0_ec_write_config(cnt, L2X0_EVENT_CONFIG_DISABLED);
+
+ /*
+ * Ok, set the counter value
+ */
+ val = -(u32)counter_config[COUNTER_L2X0_EC(cnt)].count;
+ writel(val, l2x0_base + L2X0_EVENT_CNT0_VAL - cnt * 4);
+
+ /*
+ * Now put the counter config back to what it was before
+ */
+ l2x0_ec_write_config(cnt, temp);
+}
+
+/*
+ * Read the current value of an event counter
+ */
+static inline u32 l2x0_ec_read_value(unsigned int cnt)
+{
+ return readl(l2x0_base + L2X0_EVENT_CNT0_VAL - cnt * 4);
+}
+
+/*
+ * Enable/disable L220/L230 event counting system
+ * We assume the Event Monitoring Bus is already enabled
+ * (that is, bit 20 is set in the L2X0 Aux control register)
+ * because it can't be set while the L2X0 is enabled.
+ */
+static inline void l2x0_ec_system_setup(unsigned enable)
+{
+ u32 val;
+ unsigned cnt;
+
+ /*
+ * Enable/disable and Reset all the counters
+ */
+ val = L2X0_EVENT_CONTROL_RESET_ALL;
+ if (enable)
+ val |= L2X0_EVENT_CONTROL_ENABLE;
+ writel(val, l2x0_base + L2X0_EVENT_CNT_CTRL);
+
+ /*
+ * Set the individual counters to disabled (for now at least)
+ */
+ for (cnt = 0; cnt < L2X0_NUM_COUNTERS; ++cnt)
+ l2x0_ec_write_config(cnt, L2X0_EVENT_CONFIG_DISABLED);
+
+ /*
+ * Clear any stray EC interrupt, and set the mask appropriately
+ */
+ writel(L2X0_INTR_ECNTR, l2x0_base + L2X0_INTR_CLEAR);
+ val = readl(l2x0_base + L2X0_INTR_MASK);
+ if (enable)
+ val |= L2X0_INTR_ECNTR;
+ else
+ val &= !L2X0_INTR_ECNTR;
+ writel(val, l2x0_base + L2X0_INTR_MASK);
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Rotate L220/L230 EC interrupts around all the online CPUs in an SMP system.
+ * We do this because we can't know which CPU caused an L220/L230 event,
+ * and this gives us a sensible statistical picture of what was running.
+ * This function is always called in interrupt context.
+ */
+static inline void l2x0_ec_rotate_irq(int irq)
+{
+ static unsigned cpu = 0;
+ cpumask_t mask;
+
+ if (is_smp()) {
+ cpu = next_cpu(cpu, cpu_online_map);
+ if (cpu >= NR_CPUS)
+ cpu = first_cpu(cpu_online_map);
+ mask = cpumask_of_cpu(cpu);
+ irq_set_affinity(irq, mask);
+ }
+}
+#endif
+
+/*
+ * L220/L230 event counter IRQ handler (
+ */
+static irqreturn_t l2x0_ec_interrupt(int irq, void *arg)
+{
+ u32 interrupt_status;
+ unsigned int cnt;
+
+ /* If it's an L2X0 EC interrupt, process it */
+ interrupt_status = readl(l2x0_base + L2X0_MASKED_INTR_STAT);
+
+ if (interrupt_status & L2X0_INTR_ECNTR) {
+ /*
+ * A counter that has overflowed reads 0xffffffff
+ * This is not actually documented anywhere...
+ */
+ for (cnt = 0; cnt < L2X0_NUM_COUNTERS; ++cnt) {
+ if (l2x0_ec_read_value(cnt) == 0xffffffff) {
+ oprofile_add_sample(get_irq_regs(),
+ COUNTER_L2X0_EC(cnt));
+ l2x0_ec_reset(cnt);
+ }
+ }
+ /*
+ * Clear the interrupt, and move it onto the next CPU.
+ */
+ writel(L2X0_INTR_ECNTR, l2x0_base + L2X0_INTR_CLEAR);
+#ifdef CONFIG_SMP
+ l2x0_ec_rotate_irq(irq);
+#endif
+ return IRQ_HANDLED;
+ }
+ else {
+ return IRQ_NONE;
+ }
+}
+
+int l2x0_ec_start(void)
+{
+ int ret = 0;
+ unsigned cnt;
+ u32 cfg;
+
+ /*
+ * Install handler for the L220/L230 event counter interrupt
+ */
+ ret = request_irq(l2x0_irq, l2x0_ec_interrupt, IRQF_DISABLED,
+ "L2X0 EC", NULL);
+ if (ret) {
+ printk(KERN_ERR "oprofile: unable to request IRQ%u "
+ "for L2X0 Event Counter\n", l2x0_irq);
+ return ret;
+ }
+
+ /*
+ * Enable the event counter system
+ */
+ l2x0_ec_system_setup(1);
+
+ /*
+ * Configure the events we're interested in, and reset the counters
+ */
+ for (cnt = 0; cnt < L2X0_NUM_COUNTERS; ++cnt) {
+ if (counter_config[COUNTER_L2X0_EC(cnt)].enabled) {
+ cfg = counter_config[COUNTER_L2X0_EC(cnt)].event & 0xFF;
+ cfg <<= 2;
+ cfg |= L2X0_EVENT_INTERRUPT_ON_OVF;
+ l2x0_ec_write_config(cnt, cfg);
+ l2x0_ec_reset(cnt);
+ }
+ else
+ l2x0_ec_write_config(cnt, L2X0_EVENT_CONFIG_DISABLED);
+ }
+
+ return 0;
+}
+
+void l2x0_ec_stop(void)
+{
+ unsigned cnt;
+
+ /* Disable individual L220/L230 event counters */
+ for (cnt = 0; cnt < L2X0_NUM_COUNTERS; ++cnt)
+ l2x0_ec_write_config(cnt, L2X0_EVENT_CONFIG_DISABLED);
+
+ /* Disable L220/L230 event counter system */
+ l2x0_ec_system_setup(0);
+
+ /* Remove L220/L230 event counter interrupt handler */
+ free_irq(l2x0_irq, NULL);
+}
diff --git a/arch/arm/oprofile/op_l2x0.h b/arch/arm/oprofile/op_l2x0.h
new file mode 100644
index 000000000000..8ec2df7b183d
--- /dev/null
+++ b/arch/arm/oprofile/op_l2x0.h
@@ -0,0 +1,15 @@
+/**
+ * @file op_model_l220.h
+ * ARM L220/L230 Level 2 Cache Controller Event Counter Driver
+ * @remark Copyright 2007 ARM SMP Development Team
+ *
+ * @remark Read the file COPYING
+ */
+#ifndef OP_MODEL_L2X0_H
+#define OP_MODEL_L2X0_H
+
+void l2x0_ec_setup(void);
+int l2x0_ec_start(void);
+void l2x0_ec_stop(void);
+
+#endif
diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c
index ad80752cb9fb..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_arm11_core.c
+++ b/arch/arm/oprofile/op_model_arm11_core.c
@@ -1,162 +0,0 @@
-/**
- * @file op_model_arm11_core.c
- * ARM11 Event Monitor Driver
- * @remark Copyright 2004 ARM SMP Development Team
- */
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/oprofile.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/smp.h>
-
-#include "op_counter.h"
-#include "op_arm_model.h"
-#include "op_model_arm11_core.h"
-
-/*
- * ARM11 PMU support
- */
-static inline void arm11_write_pmnc(u32 val)
-{
- /* upper 4bits and 7, 11 are write-as-0 */
- val &= 0x0ffff77f;
- asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
-}
-
-static inline u32 arm11_read_pmnc(void)
-{
- u32 val;
- asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
- return val;
-}
-
-static void arm11_reset_counter(unsigned int cnt)
-{
- u32 val = -(u32)counter_config[CPU_COUNTER(smp_processor_id(), cnt)].count;
- switch (cnt) {
- case CCNT:
- asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
- break;
-
- case PMN0:
- asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
- break;
-
- case PMN1:
- asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
- break;
- }
-}
-
-int arm11_setup_pmu(void)
-{
- unsigned int cnt;
- u32 pmnc;
-
- if (arm11_read_pmnc() & PMCR_E) {
- printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", smp_processor_id());
- return -EBUSY;
- }
-
- /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
- arm11_write_pmnc(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
- PMCR_C | PMCR_P);
-
- for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
- unsigned long event;
-
- if (!counter_config[CPU_COUNTER(smp_processor_id(), cnt)].enabled)
- continue;
-
- event = counter_config[CPU_COUNTER(smp_processor_id(), cnt)].event & 255;
-
- /*
- * Set event (if destined for PMNx counters)
- */
- if (cnt == PMN0) {
- pmnc |= event << 20;
- } else if (cnt == PMN1) {
- pmnc |= event << 12;
- }
-
- /*
- * We don't need to set the event if it's a cycle count
- * Enable interrupt for this counter
- */
- pmnc |= PMCR_IEN_PMN0 << cnt;
- arm11_reset_counter(cnt);
- }
- arm11_write_pmnc(pmnc);
-
- return 0;
-}
-
-int arm11_start_pmu(void)
-{
- arm11_write_pmnc(arm11_read_pmnc() | PMCR_E);
- return 0;
-}
-
-int arm11_stop_pmu(void)
-{
- unsigned int cnt;
-
- arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E);
-
- for (cnt = PMN0; cnt <= CCNT; cnt++)
- arm11_reset_counter(cnt);
-
- return 0;
-}
-
-/*
- * CPU counters' IRQ handler (one IRQ per CPU)
- */
-static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
-{
- struct pt_regs *regs = get_irq_regs();
- unsigned int cnt;
- u32 pmnc;
-
- pmnc = arm11_read_pmnc();
-
- for (cnt = PMN0; cnt <= CCNT; cnt++) {
- if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) {
- arm11_reset_counter(cnt);
- oprofile_add_sample(regs, CPU_COUNTER(smp_processor_id(), cnt));
- }
- }
- /* Clear counter flag(s) */
- arm11_write_pmnc(pmnc);
- return IRQ_HANDLED;
-}
-
-int arm11_request_interrupts(int *irqs, int nr)
-{
- unsigned int i;
- int ret = 0;
-
- for(i = 0; i < nr; i++) {
- ret = request_irq(irqs[i], arm11_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL);
- if (ret != 0) {
- printk(KERN_ERR "oprofile: unable to request IRQ%u for MPCORE-EM\n",
- irqs[i]);
- break;
- }
- }
-
- if (i != nr)
- while (i-- != 0)
- free_irq(irqs[i], NULL);
-
- return ret;
-}
-
-void arm11_release_interrupts(int *irqs, int nr)
-{
- unsigned int i;
-
- for (i = 0; i < nr; i++)
- free_irq(irqs[i], NULL);
-}
diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h
index 6f8538e5a960..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_arm11_core.h
+++ b/arch/arm/oprofile/op_model_arm11_core.h
@@ -1,45 +0,0 @@
-/**
- * @file op_model_arm11_core.h
- * ARM11 Event Monitor Driver
- * @remark Copyright 2004 ARM SMP Development Team
- * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
- * @remark Copyright 2000-2004 MontaVista Software Inc
- * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
- * @remark Copyright 2004 Intel Corporation
- * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
- * @remark Copyright 2004 Oprofile Authors
- *
- * @remark Read the file COPYING
- *
- * @author Zwane Mwaikambo
- */
-#ifndef OP_MODEL_ARM11_CORE_H
-#define OP_MODEL_ARM11_CORE_H
-
-/*
- * Per-CPU PMCR
- */
-#define PMCR_E (1 << 0) /* Enable */
-#define PMCR_P (1 << 1) /* Count reset */
-#define PMCR_C (1 << 2) /* Cycle counter reset */
-#define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */
-#define PMCR_IEN_PMN0 (1 << 4) /* Interrupt enable count reg 0 */
-#define PMCR_IEN_PMN1 (1 << 5) /* Interrupt enable count reg 1 */
-#define PMCR_IEN_CCNT (1 << 6) /* Interrupt enable cycle counter */
-#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
-#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
-#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
-
-#define PMN0 0
-#define PMN1 1
-#define CCNT 2
-
-#define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter))
-
-int arm11_setup_pmu(void);
-int arm11_start_pmu(void);
-int arm11_stop_pmu(void);
-int arm11_request_interrupts(int *, int);
-void arm11_release_interrupts(int *, int);
-
-#endif
diff --git a/arch/arm/oprofile/op_model_mpcore.h b/arch/arm/oprofile/op_model_mpcore.h
index 73d811023688..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_mpcore.h
+++ b/arch/arm/oprofile/op_model_mpcore.h
@@ -1,61 +0,0 @@
-/**
- * @file op_model_mpcore.c
- * MPCORE Event Monitor Driver
- * @remark Copyright 2004 ARM SMP Development Team
- * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
- * @remark Copyright 2000-2004 MontaVista Software Inc
- * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
- * @remark Copyright 2004 Intel Corporation
- * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
- * @remark Copyright 2004 Oprofile Authors
- *
- * @remark Read the file COPYING
- *
- * @author Zwane Mwaikambo
- */
-#ifndef OP_MODEL_MPCORE_H
-#define OP_MODEL_MPCORE_H
-
-struct eventmonitor {
- unsigned long PMCR;
- unsigned char MCEB[8];
- unsigned long MC[8];
-};
-
-/*
- * List of userspace counter numbers: note that the structure is important.
- * The code relies on CPUn's counters being CPU0's counters + 3n
- * and on CPU0's counters starting at 0
- */
-
-#define COUNTER_CPU0_PMN0 0
-#define COUNTER_CPU0_PMN1 1
-#define COUNTER_CPU0_CCNT 2
-
-#define COUNTER_CPU1_PMN0 3
-#define COUNTER_CPU1_PMN1 4
-#define COUNTER_CPU1_CCNT 5
-
-#define COUNTER_CPU2_PMN0 6
-#define COUNTER_CPU2_PMN1 7
-#define COUNTER_CPU2_CCNT 8
-
-#define COUNTER_CPU3_PMN0 9
-#define COUNTER_CPU3_PMN1 10
-#define COUNTER_CPU3_CCNT 11
-
-#define COUNTER_SCU_MN0 12
-#define COUNTER_SCU_MN1 13
-#define COUNTER_SCU_MN2 14
-#define COUNTER_SCU_MN3 15
-#define COUNTER_SCU_MN4 16
-#define COUNTER_SCU_MN5 17
-#define COUNTER_SCU_MN6 18
-#define COUNTER_SCU_MN7 19
-#define NUM_SCU_COUNTERS 8
-
-#define SCU_COUNTER(number) ((number) + COUNTER_SCU_MN0)
-
-#define MPCORE_NUM_COUNTERS SCU_COUNTER(NUM_SCU_COUNTERS)
-
-#endif
diff --git a/arch/arm/oprofile/op_model_v6-7.c b/arch/arm/oprofile/op_model_v6-7.c
new file mode 100644
index 000000000000..6108a91331f7
--- /dev/null
+++ b/arch/arm/oprofile/op_model_v6-7.c
@@ -0,0 +1,243 @@
+/**
+ * @file op_model_v6-7.c
+ * ARM V6 and V7 Performance Monitor models
+ *
+ * Based on op_model_xscale.c
+ *
+ * @remark Copyright 2007 ARM SMP Development Team
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 OProfile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Tony Lindgren <tony@atomide.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <linux/smp.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_arm11.h"
+#include "op_v7.h"
+#include "op_scu.h"
+#include "op_l2x0.h"
+
+static int arm11_irqs[] = {
+ [0] = IRQ_PMU_CPU0,
+#ifdef CONFIG_SMP
+ [1] = IRQ_PMU_CPU1,
+ [2] = IRQ_PMU_CPU2,
+ [3] = IRQ_PMU_CPU3
+#endif
+};
+
+static int v7_irqs[] = {
+ [0] = IRQ_PMU_CPU0,
+#ifdef CONFIG_SMP
+ [1] = IRQ_PMU_CPU1,
+ [2] = IRQ_PMU_CPU2,
+ [3] = IRQ_PMU_CPU3
+#endif
+};
+
+
+/*
+ * Functions and struct to enable calling a function on all CPUs in an SMP
+ * system. This works on a non-SMP system too (i.e. just calls the function!)
+ */
+struct em_function_data {
+ int (*fn)(void);
+ int ret;
+};
+
+static void em_func(void *data)
+{
+ struct em_function_data *d = data;
+ int ret = d->fn();
+ if (ret)
+ d->ret = ret;
+}
+
+static int em_call_function(int (*fn)(void))
+{
+ struct em_function_data data;
+
+ data.fn = fn;
+ data.ret = 0;
+
+ get_cpu();
+ if (is_smp())
+ smp_call_function(em_func, &data, 1);
+ em_func(&data);
+ put_cpu();
+
+ return data.ret;
+}
+
+
+/*
+ * Why isn't there a function to route an IRQ to a specific CPU in
+ * genirq?
+ */
+#ifdef CONFIG_SMP
+void em_route_irq(int irq, unsigned int cpu)
+{
+ irq_set_affinity(irq, *(get_cpu_mask(cpu)));
+}
+#endif
+
+/*
+ * ARM V6 Oprofile callbacks
+ */
+static void v6_stop(void)
+{
+ em_call_function(arm11_stop_pmu);
+ arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+ if (is_smp())
+ scu_stop();
+ if (have_l2x0())
+ l2x0_ec_stop();
+}
+
+static int v6_start(void)
+{
+ int ret;
+#ifdef CONFIG_SMP
+ unsigned i;
+
+ if (is_smp()) {
+ /*
+ * Send SCU and CP15 PMU interrupts to the "owner" CPU.
+ */
+ for (i=0; i<CONFIG_NR_CPUS; ++i) {
+ em_route_irq(IRQ_PMU_SCU0 + 2 * i, i);
+ em_route_irq(IRQ_PMU_SCU1 + 2 * i, i);
+ em_route_irq(IRQ_PMU_CPU0 + i, i);
+ }
+ }
+#endif
+
+ ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+ if (ret == 0) {
+ em_call_function(arm11_start_pmu);
+
+ if (is_smp())
+ ret = scu_start();
+
+ if (!ret && have_l2x0())
+ ret = l2x0_ec_start();
+
+ if (ret)
+ arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+ }
+ return ret;
+}
+
+static int v6_init(void)
+{
+ return 0;
+}
+
+static int v6_setup_ctrs(void)
+{
+ int ret;
+ ret = em_call_function(arm11_setup_pmu);
+
+ if (ret == 0 && is_smp())
+ scu_setup();
+
+ if (ret == 0 && have_l2x0())
+ l2x0_ec_setup();
+
+ return ret;
+}
+
+/*
+ * ARM V7 Oprofile callbacks
+ */
+static int v7_init(void)
+{
+ return 0;
+}
+
+
+static int v7_setup_ctrs(void)
+{
+ int ret;
+
+ ret = em_call_function(v7_setup_pmu);
+
+ if (ret == 0 && have_l2x0())
+ l2x0_ec_setup();
+
+ return ret;
+}
+
+static int v7_start(void)
+{
+ int ret;
+#ifdef CONFIG_SMP
+ unsigned i;
+
+ if (is_smp()) {
+ /*
+ * Send CP15 PMU interrupts to the owner CPU.
+ */
+ for (i=0; i<CONFIG_NR_CPUS; ++i) {
+ em_route_irq(IRQ_PMU_CPU0 + i, i);
+ }
+ }
+#endif
+
+ ret = v7_request_interrupts(v7_irqs, ARRAY_SIZE(v7_irqs));
+ if (ret == 0) {
+ em_call_function(v7_start_pmu);
+
+ if (have_l2x0())
+ ret = l2x0_ec_start();
+
+ if (ret)
+ v7_release_interrupts(v7_irqs, ARRAY_SIZE(v7_irqs));
+ }
+ return ret;
+}
+
+static void v7_stop(void)
+{
+ em_call_function(v7_stop_pmu);
+ v7_release_interrupts(v7_irqs, ARRAY_SIZE(v7_irqs));
+ if (have_l2x0())
+ l2x0_ec_stop();
+}
+
+
+struct op_arm_model_spec op_armv6_spec = {
+ .init = v6_init,
+ .num_counters = NUM_COUNTERS,
+ .setup_ctrs = v6_setup_ctrs,
+ .start = v6_start,
+ .stop = v6_stop,
+ .name = "arm/v6", /* This may get overwritten in common.c */
+};
+
+struct op_arm_model_spec op_armv7_spec = {
+ .init = v7_init,
+ .num_counters = NUM_COUNTERS,
+ .setup_ctrs = v7_setup_ctrs,
+ .start = v7_start,
+ .stop = v7_stop,
+ .name = "arm/v7", /* This gets overwritten in common.c */
+};
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
index fe581383d3e2..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_v6.c
+++ b/arch/arm/oprofile/op_model_v6.c
@@ -1,67 +0,0 @@
-/**
- * @file op_model_v6.c
- * ARM11 Performance Monitor Driver
- *
- * Based on op_model_xscale.c
- *
- * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
- * @remark Copyright 2000-2004 MontaVista Software Inc
- * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
- * @remark Copyright 2004 Intel Corporation
- * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
- * @remark Copyright 2004 OProfile Authors
- *
- * @remark Read the file COPYING
- *
- * @author Tony Lindgren <tony@atomide.com>
- */
-
-/* #define DEBUG */
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/oprofile.h>
-#include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "op_counter.h"
-#include "op_arm_model.h"
-#include "op_model_arm11_core.h"
-
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP2
- 3,
-#endif
-};
-
-static void armv6_pmu_stop(void)
-{
- arm11_stop_pmu();
- arm11_release_interrupts(irqs, ARRAY_SIZE(irqs));
-}
-
-static int armv6_pmu_start(void)
-{
- int ret;
-
- ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs));
- if (ret >= 0)
- ret = arm11_start_pmu();
-
- return ret;
-}
-
-static int armv6_detect_pmu(void)
-{
- return 0;
-}
-
-struct op_arm_model_spec op_armv6_spec = {
- .init = armv6_detect_pmu,
- .num_counters = 3,
- .setup_ctrs = arm11_setup_pmu,
- .start = armv6_pmu_start,
- .stop = armv6_pmu_stop,
- .name = "arm/armv6",
-};
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
index f20295f14adb..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_v7.c
+++ b/arch/arm/oprofile/op_model_v7.c
@@ -1,411 +0,0 @@
-/**
- * op_model_v7.c
- * ARM V7 (Cortex A8) Event Monitor Driver
- *
- * Copyright 2008 Jean Pihet <jpihet@mvista.com>
- * Copyright 2004 ARM SMP Development Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/oprofile.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/smp.h>
-
-#include "op_counter.h"
-#include "op_arm_model.h"
-#include "op_model_v7.h"
-
-/* #define DEBUG */
-
-
-/*
- * ARM V7 PMNC support
- */
-
-static u32 cnt_en[CNTMAX];
-
-static inline void armv7_pmnc_write(u32 val)
-{
- val &= PMNC_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
-}
-
-static inline u32 armv7_pmnc_read(void)
-{
- u32 val;
-
- asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
- return val;
-}
-
-static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
-{
- u32 val;
-
- if (cnt >= CNTMAX) {
- printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
- " %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- if (cnt == CCNT)
- val = CNTENS_C;
- else
- val = (1 << (cnt - CNT0));
-
- val &= CNTENS_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
-
- return cnt;
-}
-
-static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
-{
- u32 val;
-
- if (cnt >= CNTMAX) {
- printk(KERN_ERR "oprofile: CPU%u disabling wrong PMNC counter"
- " %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- if (cnt == CCNT)
- val = CNTENC_C;
- else
- val = (1 << (cnt - CNT0));
-
- val &= CNTENC_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
-
- return cnt;
-}
-
-static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
-{
- u32 val;
-
- if (cnt >= CNTMAX) {
- printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
- " interrupt enable %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- if (cnt == CCNT)
- val = INTENS_C;
- else
- val = (1 << (cnt - CNT0));
-
- val &= INTENS_MASK;
- asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
-
- return cnt;
-}
-
-static inline u32 armv7_pmnc_getreset_flags(void)
-{
- u32 val;
-
- /* Read */
- asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
-
- /* Write to clear flags */
- val &= FLAG_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
-
- return val;
-}
-
-static inline int armv7_pmnc_select_counter(unsigned int cnt)
-{
- u32 val;
-
- if ((cnt == CCNT) || (cnt >= CNTMAX)) {
- printk(KERN_ERR "oprofile: CPU%u selecting wrong PMNC counteri"
- " %d\n", smp_processor_id(), cnt);
- return -1;
- }
-
- val = (cnt - CNT0) & SELECT_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
-
- return cnt;
-}
-
-static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
-{
- if (armv7_pmnc_select_counter(cnt) == cnt) {
- val &= EVTSEL_MASK;
- asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
- }
-}
-
-static void armv7_pmnc_reset_counter(unsigned int cnt)
-{
- u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
- u32 val = -(u32)counter_config[cpu_cnt].count;
-
- switch (cnt) {
- case CCNT:
- armv7_pmnc_disable_counter(cnt);
-
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
-
- if (cnt_en[cnt] != 0)
- armv7_pmnc_enable_counter(cnt);
-
- break;
-
- case CNT0:
- case CNT1:
- case CNT2:
- case CNT3:
- armv7_pmnc_disable_counter(cnt);
-
- if (armv7_pmnc_select_counter(cnt) == cnt)
- asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
-
- if (cnt_en[cnt] != 0)
- armv7_pmnc_enable_counter(cnt);
-
- break;
-
- default:
- printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter"
- " %d\n", smp_processor_id(), cnt);
- break;
- }
-}
-
-int armv7_setup_pmnc(void)
-{
- unsigned int cnt;
-
- if (armv7_pmnc_read() & PMNC_E) {
- printk(KERN_ERR "oprofile: CPU%u PMNC still enabled when setup"
- " new event counter.\n", smp_processor_id());
- return -EBUSY;
- }
-
- /*
- * Initialize & Reset PMNC: C bit, D bit and P bit.
- * Note: Using a slower count for CCNT (D bit: divide by 64) results
- * in a more stable system
- */
- armv7_pmnc_write(PMNC_P | PMNC_C | PMNC_D);
-
-
- for (cnt = CCNT; cnt < CNTMAX; cnt++) {
- unsigned long event;
- u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
-
- /*
- * Disable counter
- */
- armv7_pmnc_disable_counter(cnt);
- cnt_en[cnt] = 0;
-
- if (!counter_config[cpu_cnt].enabled)
- continue;
-
- event = counter_config[cpu_cnt].event & 255;
-
- /*
- * Set event (if destined for PMNx counters)
- * We don't need to set the event if it's a cycle count
- */
- if (cnt != CCNT)
- armv7_pmnc_write_evtsel(cnt, event);
-
- /*
- * Enable interrupt for this counter
- */
- armv7_pmnc_enable_intens(cnt);
-
- /*
- * Reset counter
- */
- armv7_pmnc_reset_counter(cnt);
-
- /*
- * Enable counter
- */
- armv7_pmnc_enable_counter(cnt);
- cnt_en[cnt] = 1;
- }
-
- return 0;
-}
-
-static inline void armv7_start_pmnc(void)
-{
- armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
-}
-
-static inline void armv7_stop_pmnc(void)
-{
- armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
-}
-
-/*
- * CPU counters' IRQ handler (one IRQ per CPU)
- */
-static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
-{
- struct pt_regs *regs = get_irq_regs();
- unsigned int cnt;
- u32 flags;
-
-
- /*
- * Stop IRQ generation
- */
- armv7_stop_pmnc();
-
- /*
- * Get and reset overflow status flags
- */
- flags = armv7_pmnc_getreset_flags();
-
- /*
- * Cycle counter
- */
- if (flags & FLAG_C) {
- u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), CCNT);
- armv7_pmnc_reset_counter(CCNT);
- oprofile_add_sample(regs, cpu_cnt);
- }
-
- /*
- * PMNC counters 0:3
- */
- for (cnt = CNT0; cnt < CNTMAX; cnt++) {
- if (flags & (1 << (cnt - CNT0))) {
- u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
- armv7_pmnc_reset_counter(cnt);
- oprofile_add_sample(regs, cpu_cnt);
- }
- }
-
- /*
- * Allow IRQ generation
- */
- armv7_start_pmnc();
-
- return IRQ_HANDLED;
-}
-
-int armv7_request_interrupts(int *irqs, int nr)
-{
- unsigned int i;
- int ret = 0;
-
- for (i = 0; i < nr; i++) {
- ret = request_irq(irqs[i], armv7_pmnc_interrupt,
- IRQF_DISABLED, "CP15 PMNC", NULL);
- if (ret != 0) {
- printk(KERN_ERR "oprofile: unable to request IRQ%u"
- " for ARMv7\n",
- irqs[i]);
- break;
- }
- }
-
- if (i != nr)
- while (i-- != 0)
- free_irq(irqs[i], NULL);
-
- return ret;
-}
-
-void armv7_release_interrupts(int *irqs, int nr)
-{
- unsigned int i;
-
- for (i = 0; i < nr; i++)
- free_irq(irqs[i], NULL);
-}
-
-#ifdef DEBUG
-static void armv7_pmnc_dump_regs(void)
-{
- u32 val;
- unsigned int cnt;
-
- printk(KERN_INFO "PMNC registers dump:\n");
-
- asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
- printk(KERN_INFO "PMNC =0x%08x\n", val);
-
- asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
- printk(KERN_INFO "CNTENS=0x%08x\n", val);
-
- asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
- printk(KERN_INFO "INTENS=0x%08x\n", val);
-
- asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
- printk(KERN_INFO "FLAGS =0x%08x\n", val);
-
- asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
- printk(KERN_INFO "SELECT=0x%08x\n", val);
-
- asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
- printk(KERN_INFO "CCNT =0x%08x\n", val);
-
- for (cnt = CNT0; cnt < CNTMAX; cnt++) {
- armv7_pmnc_select_counter(cnt);
- asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
- printk(KERN_INFO "CNT[%d] count =0x%08x\n", cnt-CNT0, val);
- asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
- printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", cnt-CNT0, val);
- }
-}
-#endif
-
-
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP3
- INT_34XX_BENCH_MPU_EMUL,
-#endif
-};
-
-static void armv7_pmnc_stop(void)
-{
-#ifdef DEBUG
- armv7_pmnc_dump_regs();
-#endif
- armv7_stop_pmnc();
- armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
-}
-
-static int armv7_pmnc_start(void)
-{
- int ret;
-
-#ifdef DEBUG
- armv7_pmnc_dump_regs();
-#endif
- ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
- if (ret >= 0)
- armv7_start_pmnc();
-
- return ret;
-}
-
-static int armv7_detect_pmnc(void)
-{
- return 0;
-}
-
-struct op_arm_model_spec op_armv7_spec = {
- .init = armv7_detect_pmnc,
- .num_counters = 5,
- .setup_ctrs = armv7_setup_pmnc,
- .start = armv7_pmnc_start,
- .stop = armv7_pmnc_stop,
- .name = "arm/armv7",
-};
diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
index 0e19bcc2e100..e69de29bb2d1 100644
--- a/arch/arm/oprofile/op_model_v7.h
+++ b/arch/arm/oprofile/op_model_v7.h
@@ -1,103 +0,0 @@
-/**
- * op_model_v7.h
- * ARM v7 (Cortex A8) Event Monitor Driver
- *
- * Copyright 2008 Jean Pihet <jpihet@mvista.com>
- * Copyright 2004 ARM SMP Development Team
- * Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
- * Copyright 2000-2004 MontaVista Software Inc
- * Copyright 2004 Dave Jiang <dave.jiang@intel.com>
- * Copyright 2004 Intel Corporation
- * Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
- * Copyright 2004 Oprofile Authors
- *
- * Read the file COPYING
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef OP_MODEL_V7_H
-#define OP_MODEL_V7_H
-
-/*
- * Per-CPU PMNC: config reg
- */
-#define PMNC_E (1 << 0) /* Enable all counters */
-#define PMNC_P (1 << 1) /* Reset all counters */
-#define PMNC_C (1 << 2) /* Cycle counter reset */
-#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
-#define PMNC_X (1 << 4) /* Export to ETM */
-#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
-#define PMNC_MASK 0x3f /* Mask for writable bits */
-
-/*
- * Available counters
- */
-#define CCNT 0
-#define CNT0 1
-#define CNT1 2
-#define CNT2 3
-#define CNT3 4
-#define CNTMAX 5
-
-#define CPU_COUNTER(cpu, counter) ((cpu) * CNTMAX + (counter))
-
-/*
- * CNTENS: counters enable reg
- */
-#define CNTENS_P0 (1 << 0)
-#define CNTENS_P1 (1 << 1)
-#define CNTENS_P2 (1 << 2)
-#define CNTENS_P3 (1 << 3)
-#define CNTENS_C (1 << 31)
-#define CNTENS_MASK 0x8000000f /* Mask for writable bits */
-
-/*
- * CNTENC: counters disable reg
- */
-#define CNTENC_P0 (1 << 0)
-#define CNTENC_P1 (1 << 1)
-#define CNTENC_P2 (1 << 2)
-#define CNTENC_P3 (1 << 3)
-#define CNTENC_C (1 << 31)
-#define CNTENC_MASK 0x8000000f /* Mask for writable bits */
-
-/*
- * INTENS: counters overflow interrupt enable reg
- */
-#define INTENS_P0 (1 << 0)
-#define INTENS_P1 (1 << 1)
-#define INTENS_P2 (1 << 2)
-#define INTENS_P3 (1 << 3)
-#define INTENS_C (1 << 31)
-#define INTENS_MASK 0x8000000f /* Mask for writable bits */
-
-/*
- * EVTSEL: Event selection reg
- */
-#define EVTSEL_MASK 0x7f /* Mask for writable bits */
-
-/*
- * SELECT: Counter selection reg
- */
-#define SELECT_MASK 0x1f /* Mask for writable bits */
-
-/*
- * FLAG: counters overflow flag status reg
- */
-#define FLAG_P0 (1 << 0)
-#define FLAG_P1 (1 << 1)
-#define FLAG_P2 (1 << 2)
-#define FLAG_P3 (1 << 3)
-#define FLAG_C (1 << 31)
-#define FLAG_MASK 0x8000000f /* Mask for writable bits */
-
-
-int armv7_setup_pmu(void);
-int armv7_start_pmu(void);
-int armv7_stop_pmu(void);
-int armv7_request_interrupts(int *, int);
-void armv7_release_interrupts(int *, int);
-
-#endif
diff --git a/arch/arm/oprofile/op_scu.c b/arch/arm/oprofile/op_scu.c
new file mode 100644
index 000000000000..62186f0acc82
--- /dev/null
+++ b/arch/arm/oprofile/op_scu.c
@@ -0,0 +1,175 @@
+/**
+ * @file op_scu.c
+ * MPCORE Snoop Control Unit Event Monitor Driver
+ * @remark Copyright 2004-7 ARM SMP Development Team
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 Oprofile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Zwane Mwaikambo
+ *
+ */
+
+/* #define DEBUG */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/system.h>
+#include <mach/hardware.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_scu.h"
+
+struct eventmonitor {
+ unsigned long PMCR;
+ unsigned char MCEB[8];
+ unsigned long MC[8];
+};
+
+#define PMCR_E 1
+
+/*
+ * Bitmask of used SCU counters
+ */
+static unsigned int scu_em_used;
+
+/*
+ * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
+ */
+static inline void scu_reset_counter(struct eventmonitor __iomem *emc, unsigned int n)
+{
+ writel(-(u32)counter_config[COUNTER_SCU_MN(n)].count, &emc->MC[n]);
+}
+
+static inline void scu_set_event(struct eventmonitor __iomem *emc, unsigned int n, u32 event)
+{
+ event &= 0xff;
+ writeb(event, &emc->MCEB[n]);
+}
+
+/*
+ * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU)
+ */
+static irqreturn_t scu_em_interrupt(int irq, void *arg)
+{
+ struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
+ unsigned int cnt, tmp;
+
+ cnt = irq - IRQ_PMU_SCU0;
+ oprofile_add_sample(get_irq_regs(), COUNTER_SCU_MN(cnt));
+ scu_reset_counter(emc, cnt);
+
+ /* Clear overflow flag for this counter */
+ tmp = readl(&emc->PMCR);
+ tmp &= 0xff00ffff; /* mask out any other overflow flags */
+ tmp |= 1 << (cnt + 16);
+ writel(tmp, &emc->PMCR);
+
+ return IRQ_HANDLED;
+}
+
+/* Configure just the SCU counters that the user has requested */
+void scu_setup(void)
+{
+ struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
+ unsigned int i;
+
+ scu_em_used = 0;
+
+ for (i = 0; i < NUM_SCU_COUNTERS; i++) {
+ if (counter_config[COUNTER_SCU_MN(i)].enabled &&
+ counter_config[COUNTER_SCU_MN(i)].event) {
+ scu_set_event(emc, i, 0); /* disable counter for now */
+ scu_em_used |= 1 << i;
+ }
+ }
+}
+
+int scu_start(void)
+{
+ struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
+ unsigned int temp, i;
+ unsigned long event;
+ int ret = 0;
+
+ /*
+ * request the SCU counter interrupts that we need
+ */
+ for (i = 0; i < NUM_SCU_COUNTERS; i++) {
+ if (scu_em_used & (1 << i)) {
+ ret = request_irq(IRQ_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED,
+ "SCU PMU", NULL);
+ if (ret) {
+ printk(KERN_ERR
+ "oprofile: unable to request IRQ%u for SCU Event Monitor\n",
+ IRQ_PMU_SCU0 + i);
+ goto err_free_scu;
+ }
+ }
+ }
+
+ /*
+ * clear overflow and enable interrupt for all used counters
+ */
+ temp = readl(&emc->PMCR);
+ for (i = 0; i < NUM_SCU_COUNTERS; i++) {
+ if (scu_em_used & (1 << i)) {
+ scu_reset_counter(emc, i);
+ event = counter_config[COUNTER_SCU_MN(i)].event;
+ scu_set_event(emc, i, event);
+
+ /* clear overflow/interrupt */
+ temp |= 1 << (i + 16);
+ /* enable interrupt*/
+ temp |= 1 << (i + 8);
+ }
+ }
+
+ /* Enable all 8 counters */
+ temp |= PMCR_E;
+ writel(temp, &emc->PMCR);
+
+ return 0;
+
+ err_free_scu:
+ while (i--)
+ free_irq(IRQ_PMU_SCU0 + i, NULL);
+ return ret;
+}
+
+void scu_stop(void)
+{
+ struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
+ unsigned int temp, i;
+
+ /* Disable counter interrupts */
+ /* Don't disable all 8 counters (with the E bit) as they may be in use */
+ temp = readl(&emc->PMCR);
+ for (i = 0; i < NUM_SCU_COUNTERS; i++) {
+ if (scu_em_used & (1 << i))
+ temp &= ~(1 << (i + 8));
+ }
+ writel(temp, &emc->PMCR);
+
+ /* Free counter interrupts and reset counters */
+ for (i = 0; i < NUM_SCU_COUNTERS; i++) {
+ if (scu_em_used & (1 << i)) {
+ scu_reset_counter(emc, i);
+ free_irq(IRQ_PMU_SCU0 + i, NULL);
+ }
+ }
+}
+
diff --git a/arch/arm/oprofile/op_scu.h b/arch/arm/oprofile/op_scu.h
new file mode 100644
index 000000000000..572bd7df8264
--- /dev/null
+++ b/arch/arm/oprofile/op_scu.h
@@ -0,0 +1,23 @@
+/**
+ * @file op_scu.c
+ * MPCORE Snoop Control Unit Event Monitor Driver
+ * @remark Copyright 2004 ARM SMP Development Team
+ * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
+ * @remark Copyright 2000-2004 MontaVista Software Inc
+ * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
+ * @remark Copyright 2004 Intel Corporation
+ * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
+ * @remark Copyright 2004 Oprofile Authors
+ *
+ * @remark Read the file COPYING
+ *
+ * @author Zwane Mwaikambo
+ */
+#ifndef OP_SCU_H
+#define OP_SCU_H
+
+void scu_setup(void);
+int scu_start(void);
+void scu_stop(void);
+
+#endif
diff --git a/arch/arm/oprofile/op_v7.c b/arch/arm/oprofile/op_v7.c
new file mode 100644
index 000000000000..a71fcccc441e
--- /dev/null
+++ b/arch/arm/oprofile/op_v7.c
@@ -0,0 +1,248 @@
+/**
+ * @file op_v7.c
+ * ARM V7 Performance Monitor Unit Driver
+ *
+ * @remark Copyright 2007 ARM SMP Development Team
+ *
+ * @remark Read the file COPYING
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+#include "op_v7.h"
+
+/*
+ * We assume each CPU has PMU_COUNTERS_PER_CPU counters, where the
+ * last one is a cycle counter, the rest are event counters.
+ * The oprofile event files in userland should ensure that we will not
+ * access counters that aren't physically present, but we also check
+ * the counter numbers here.
+ */
+
+#define PMCR_N_MASK 0xf800
+#define PMCR_N_SHIFT 11
+
+static unsigned event_counters_per_cpu;
+
+/*
+ * ARM V7 PMU support
+ */
+static inline void v7_write_pmcr(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+static inline u32 v7_read_pmcr(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+ return val;
+}
+
+static inline void v7_reset_counter(unsigned int cpu, unsigned int cnt)
+{
+ u32 val = -(u32)counter_config[COUNTER_CPUn_PMNm(cpu, cnt)].count;
+
+ if (cnt == CCNT)
+ /* Set cycle count in PMCCNTR */
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
+ else {
+ /* Select correct counter using PMSELR */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (cnt));
+ /* Set the count value */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
+ }
+}
+
+static inline void v7_set_event(unsigned int cnt, u32 val)
+{
+ /* Select correct counter using PMSELR */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (cnt));
+ /* Set event type in PMXEVTYPER*/
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+}
+
+static inline void v7_clear_overflow_status(u32 status)
+{
+ /* Clear overflow bits in PMOVSR */
+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (status));
+}
+
+static inline u32 v7_read_overflow_status(void)
+{
+ u32 status;
+
+ /* Read overflow bits in PMOVSR */
+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (status));
+
+ return status;
+}
+
+static inline void v7_enable_counter(unsigned int cnt)
+{
+ u32 val;
+
+ if (cnt == CCNT)
+ val = PMCNTEN_CCNT;
+ else
+ val = PMCNTEN_PMN0 << cnt;
+
+ /* Set bit in PMCNTEN */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+}
+
+static inline void v7_disable_counter(unsigned int cnt)
+{
+ u32 val;
+
+ if (cnt == CCNT)
+ val = PMCNTEN_CCNT;
+ else
+ val = PMCNTEN_PMN0 << cnt;
+
+ /* Clear bit in PMCNTEN */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+}
+
+static inline void v7_set_interrupts(u32 interrupts)
+{
+ /* Clear all interrupts in PMINTENCLR */
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (0xFFFFFFFFU));
+
+ /* Set requested interrupts in PMINTENSET */
+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (interrupts));
+}
+
+int v7_setup_pmu(void)
+{
+ unsigned int cnt, cpu;
+ u32 pmcr, interrupts;
+
+ /*
+ * No need for get_cpu/put_cpu, because we were either called
+ * from em_call_function(), which itself uses get_cpu/put_cpu,
+ * or smp_call_function(), which means we are in IRQ context.
+ */
+ pmcr = v7_read_pmcr();
+ cpu = smp_processor_id();
+
+ if (pmcr & PMCR_E) {
+ printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", cpu);
+ return -EBUSY;
+ }
+
+ /* Discover the number of counters */
+ event_counters_per_cpu = (pmcr & PMCR_N_MASK) >> PMCR_N_SHIFT;
+
+ /* initialize PMNC: reset all counters, clear DP,X,D,E bits */
+ v7_write_pmcr(PMCR_C | PMCR_P);
+ for (cnt = 0; cnt < event_counters_per_cpu; cnt++)
+ v7_disable_counter(cnt);
+ v7_disable_counter(CCNT);
+
+ interrupts = 0;
+
+ /* Set up the event counters */
+ for (cnt = 0; cnt < event_counters_per_cpu; cnt++) {
+ unsigned long event;
+
+ if (!counter_config[COUNTER_CPUn_PMNm(cpu, cnt)].enabled)
+ continue;
+
+ event = counter_config[COUNTER_CPUn_PMNm(cpu, cnt)].event & 255;
+
+ v7_set_event(cnt, event);
+ v7_reset_counter(cpu, cnt);
+ v7_enable_counter(cnt);
+ interrupts |= PMINTEN_PMN0 << cnt;
+ }
+
+ /* Now set up the cycle counter */
+ if (counter_config[COUNTER_CPUn_CCNT(cpu)].enabled) {
+ v7_reset_counter(cpu, CCNT);
+ v7_enable_counter(CCNT);
+ interrupts |= PMINTEN_CCNT;
+ }
+
+ /* Enable the required interrupts */
+ v7_set_interrupts(interrupts);
+
+ return 0;
+}
+
+int v7_start_pmu(void)
+{
+ v7_write_pmcr(v7_read_pmcr() | PMCR_E);
+ return 0;
+}
+
+int v7_stop_pmu(void)
+{
+ v7_write_pmcr(v7_read_pmcr() & ~PMCR_E);
+ return 0;
+}
+
+/*
+ * CPU counters' IRQ handler (one IRQ per CPU)
+ */
+static irqreturn_t v7_pmu_interrupt(int irq, void *arg)
+{
+ struct pt_regs *regs = get_irq_regs();
+ unsigned int cnt, cpu;
+ u32 overflowed;
+
+ overflowed = v7_read_overflow_status();
+ cpu = smp_processor_id();
+
+ /* Check each event counter */
+ for (cnt = 0; cnt < CCNT; cnt++) {
+ if (overflowed & (PMOVSR_PMN0 << cnt)) {
+ v7_reset_counter(cpu, cnt);
+ oprofile_add_sample(regs, COUNTER_CPUn_PMNm(cpu, cnt));
+ }
+ }
+
+ /* Check the cycle counter */
+ if (overflowed & PMOVSR_CCNT) {
+ v7_reset_counter(cpu, CCNT);
+ oprofile_add_sample(regs, COUNTER_CPUn_CCNT(cpu));
+ }
+
+ v7_clear_overflow_status(overflowed);
+ return IRQ_HANDLED;
+}
+
+int v7_request_interrupts(int *irqs, int nr)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for(i = 0; i < nr; i++) {
+ ret = request_irq(irqs[i], v7_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL);
+ if (ret != 0) {
+ printk(KERN_ERR "oprofile: unable to request IRQ%u for CP15 PMU\n",
+ irqs[i]);
+ break;
+ }
+ }
+
+ if (i != nr)
+ while (i-- != 0)
+ free_irq(irqs[i], NULL);
+
+ return ret;
+}
+
+void v7_release_interrupts(int *irqs, int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ free_irq(irqs[i], NULL);
+}
diff --git a/arch/arm/oprofile/op_v7.h b/arch/arm/oprofile/op_v7.h
new file mode 100644
index 000000000000..03ca7dfeecf5
--- /dev/null
+++ b/arch/arm/oprofile/op_v7.h
@@ -0,0 +1,36 @@
+/**
+ * @file op_v7.h
+ * ARM V7 Performance Monitor Unit Driver
+ *
+ * @remark Copyright 2007 ARM SMP Development Team
+ *
+ * @remark Read the file COPYING
+ */
+#ifndef OP_V7_H
+#define OP_V7_H
+
+/*
+ * V7 CP15 PMU
+ */
+#define PMCR_E (1 << 0) /* Enable */
+#define PMCR_P (1 << 1) /* Count reset */
+#define PMCR_C (1 << 2) /* Cycle counter reset */
+#define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */
+
+#define PMINTEN_PMN0 (1 << 0)
+#define PMINTEN_CCNT (1 << 31)
+
+#define PMOVSR_PMN0 (1 << 0)
+#define PMOVSR_CCNT (1 << 31)
+
+#define PMCNTEN_PMN0 (1 << 0)
+#define PMCNTEN_CCNT (1 << 31)
+
+
+int v7_setup_pmu(void);
+int v7_start_pmu(void);
+int v7_stop_pmu(void);
+int v7_request_interrupts(int *, int);
+void v7_release_interrupts(int *, int);
+
+#endif
diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
index ce319ef64bc1..223173670ad0 100644
--- a/arch/arm/tools/gen-mach-types
+++ b/arch/arm/tools/gen-mach-types
@@ -68,5 +68,11 @@ END {
printf("\n#ifndef machine_arch_type\n");
printf("#define machine_arch_type\t__machine_arch_type\n");
printf("#endif\n\n");
+
+ printf("#define __machine_arch_type\t-1\n");
+ printf("#if defined(CONFIG_NAKED_BOOT) && (machine_arch_type < 0)\n");
+ printf("#error \"CONFIG_NAKED_BOOT may be used with a single-machine config only\"\n");
+ printf("#endif\n");
+ printf("#undef __machine_arch_type\n\n");
printf("#endif\n");
}
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index b4211d8b2ac7..ccdbc266c694 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -2124,3 +2124,4 @@ mx27wallace MACH_MX27WALLACE MX27WALLACE 2133
fmzwebmodul MACH_FMZWEBMODUL FMZWEBMODUL 2134
rd78x00_masa MACH_RD78X00_MASA RD78X00_MASA 2135
smallogger MACH_SMALLOGGER SMALLOGGER 2136
+mps MACH_MPS MPS 10000
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index a2bed62aec21..4fa9903b83cf 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -42,6 +42,7 @@ ENTRY(vfp_null_entry)
mov pc, lr
ENDPROC(vfp_null_entry)
+ .align 2
.LCvfp:
.word vfp_vector
@@ -61,6 +62,7 @@ ENTRY(vfp_testing_entry)
mov pc, r9 @ we have handled the fault
ENDPROC(vfp_testing_entry)
+ .align 2
VFP_arch_address:
.word VFP_arch
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index c8c98dd44ad4..8a5fe9c6cccd 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -37,6 +37,7 @@ static inline u32 vfp_hi64to32jamming(u64 val)
asm(
"cmp %Q1, #1 @ vfp_hi64to32jamming\n\t"
+ "ite cc\n\t"
"movcc %0, %R1\n\t"
"orrcs %0, %R1, #1"
: "=r" (v) : "r" (val) : "cc");
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 83c4e384b16d..f570411e32af 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -1,5 +1,4 @@
-/*
- * linux/arch/arm/vfp/vfphw.S
+/* linux/arch/arm/vfp/vfphw.S
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
@@ -205,40 +204,52 @@ ENDPROC(vfp_save_state)
last_VFP_context_address:
.word last_VFP_context
+ .macro tbl_branch, base, tmp, shift
+ ARM( add pc, pc, \base, lsl \shift )
+ ARM( mov r0, r0 )
+ THUMB( adr \tmp, 1f )
+ THUMB( add \tmp, \tmp, \base, lsl \shift )
+ THUMB( mov pc, \tmp )
+1:
+ .endm
+
ENTRY(vfp_get_float)
- add pc, pc, r0, lsl #3
- mov r0, r0
+ tbl_branch r0, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0
+1: mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0
mov pc, lr
- mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1
+ .org 1b + 8
+1: mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1
mov pc, lr
+ .org 1b + 8
.endr
ENDPROC(vfp_get_float)
ENTRY(vfp_put_float)
- add pc, pc, r1, lsl #3
- mov r0, r0
+ tbl_branch r1, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0
+1: mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0
mov pc, lr
- mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1
+ .org 1b + 8
+1: mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1
mov pc, lr
+ .org 1b + 8
.endr
ENDPROC(vfp_put_float)
ENTRY(vfp_get_double)
- add pc, pc, r0, lsl #3
- mov r0, r0
+ tbl_branch r0, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- fmrrd r0, r1, d\dr
+1: fmrrd r0, r1, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#ifdef CONFIG_VFPv3
@ d16 - d31 registers
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr
+1: mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#endif
@@ -249,17 +260,18 @@ ENTRY(vfp_get_double)
ENDPROC(vfp_get_double)
ENTRY(vfp_put_double)
- add pc, pc, r2, lsl #3
- mov r0, r0
+ tbl_branch r2, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- fmdrr d\dr, r0, r1
+1: fmdrr d\dr, r0, r1
mov pc, lr
+ .org 1b + 8
.endr
#ifdef CONFIG_VFPv3
@ d16 - d31 registers
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr
+1: mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#endif
ENDPROC(vfp_put_double)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 01599c4ef726..503eadb31be3 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -14,6 +14,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/rcupdate.h>
#include <asm/thread_notify.h>
#include <asm/vfp.h>
@@ -49,14 +50,21 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
#ifdef CONFIG_SMP
/*
+ * RCU locking is needed in case last_VFP_context[cpu] is
+ * released on a different CPU.
+ */
+ rcu_read_lock();
+ vfp = last_VFP_context[cpu];
+ /*
* On SMP, if VFP is enabled, save the old state in
* case the thread migrates to a different CPU. The
* restoring is done lazily.
*/
- if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
- vfp_save_state(last_VFP_context[cpu], fpexc);
- last_VFP_context[cpu]->hard.cpu = cpu;
+ if ((fpexc & FPEXC_EN) && vfp) {
+ vfp_save_state(vfp, fpexc);
+ vfp->hard.cpu = cpu;
}
+ rcu_read_unlock();
/*
* Thread migration, just force the reloading of the
* state on the new CPU in case the VFP registers
@@ -91,8 +99,19 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
}
/* flush and release case: Per-thread VFP cleanup. */
+#ifndef CONFIG_SMP
if (last_VFP_context[cpu] == vfp)
last_VFP_context[cpu] = NULL;
+#else
+ /*
+ * Since release_thread() may be called from a different CPU, we use
+ * cmpxchg() here to avoid a race with the vfp_support_entry() code
+ * which modifies last_VFP_context[cpu]. Note that on SMP systems, a
+ * STR instruction on a different CPU clears the global exclusive
+ * monitor state.
+ */
+ (void)cmpxchg(&last_VFP_context[cpu], vfp, NULL);
+#endif
return NOTIFY_DONE;
}