aboutsummaryrefslogtreecommitdiff
path: root/arch/arc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/Kconfig77
-rw-r--r--arch/arc/Kconfig.debug7
-rw-r--r--arch/arc/Makefile41
-rw-r--r--arch/arc/boot/.gitignore2
-rw-r--r--arch/arc/boot/Makefile19
-rw-r--r--arch/arc/boot/dts/Makefile4
-rw-r--r--arch/arc/boot/dts/abilis_tb100.dtsi350
-rw-r--r--arch/arc/boot/dts/abilis_tb100_dvk.dts127
-rw-r--r--arch/arc/boot/dts/abilis_tb101.dtsi359
-rw-r--r--arch/arc/boot/dts/abilis_tb101_dvk.dts127
-rw-r--r--arch/arc/boot/dts/abilis_tb10x.dtsi240
-rw-r--r--arch/arc/boot/dts/angel4.dts22
-rw-r--r--arch/arc/boot/dts/nsimosci.dts79
-rw-r--r--arch/arc/boot/dts/skeleton.dts10
-rw-r--r--arch/arc/configs/fpga_defconfig11
-rw-r--r--arch/arc/configs/fpga_noramfs_defconfig64
-rw-r--r--arch/arc/configs/nsimosci_defconfig76
-rw-r--r--arch/arc/configs/tb10x_defconfig117
-rw-r--r--arch/arc/include/asm/Kbuild9
-rw-r--r--arch/arc/include/asm/arcregs.h127
-rw-r--r--arch/arc/include/asm/barrier.h42
-rw-r--r--arch/arc/include/asm/bitops.h5
-rw-r--r--arch/arc/include/asm/bug.h5
-rw-r--r--arch/arc/include/asm/cache.h62
-rw-r--r--arch/arc/include/asm/cacheflush.h77
-rw-r--r--arch/arc/include/asm/defines.h56
-rw-r--r--arch/arc/include/asm/delay.h5
-rw-r--r--arch/arc/include/asm/dma-mapping.h2
-rw-r--r--arch/arc/include/asm/elf.h3
-rw-r--r--arch/arc/include/asm/entry.h546
-rw-r--r--arch/arc/include/asm/io.h4
-rw-r--r--arch/arc/include/asm/irq.h9
-rw-r--r--arch/arc/include/asm/irqflags.h59
-rw-r--r--arch/arc/include/asm/kgdb.h8
-rw-r--r--arch/arc/include/asm/kprobes.h6
-rw-r--r--arch/arc/include/asm/linkage.h14
-rw-r--r--arch/arc/include/asm/mach_desc.h17
-rw-r--r--arch/arc/include/asm/mmu.h51
-rw-r--r--arch/arc/include/asm/mmu_context.h200
-rw-r--r--arch/arc/include/asm/page.h18
-rw-r--r--arch/arc/include/asm/perf_event.h204
-rw-r--r--arch/arc/include/asm/pgalloc.h11
-rw-r--r--arch/arc/include/asm/pgtable.h57
-rw-r--r--arch/arc/include/asm/processor.h46
-rw-r--r--arch/arc/include/asm/prom.h14
-rw-r--r--arch/arc/include/asm/ptrace.h83
-rw-r--r--arch/arc/include/asm/sections.h2
-rw-r--r--arch/arc/include/asm/serial.h10
-rw-r--r--arch/arc/include/asm/setup.h2
-rw-r--r--arch/arc/include/asm/shmparam.h18
-rw-r--r--arch/arc/include/asm/smp.h10
-rw-r--r--arch/arc/include/asm/spinlock.h9
-rw-r--r--arch/arc/include/asm/spinlock_types.h6
-rw-r--r--arch/arc/include/asm/syscall.h5
-rw-r--r--arch/arc/include/asm/syscalls.h2
-rw-r--r--arch/arc/include/asm/thread_info.h2
-rw-r--r--arch/arc/include/asm/tlb-mmu1.h4
-rw-r--r--arch/arc/include/asm/tlb.h53
-rw-r--r--arch/arc/include/asm/tlbflush.h11
-rw-r--r--arch/arc/include/asm/uaccess.h4
-rw-r--r--arch/arc/include/asm/unaligned.h7
-rw-r--r--arch/arc/include/uapi/asm/Kbuild7
-rw-r--r--arch/arc/include/uapi/asm/ptrace.h20
-rw-r--r--arch/arc/include/uapi/asm/unistd.h11
-rw-r--r--arch/arc/kernel/.gitignore1
-rw-r--r--arch/arc/kernel/Makefile1
-rw-r--r--arch/arc/kernel/asm-offsets.c9
-rw-r--r--arch/arc/kernel/clk.c2
-rw-r--r--arch/arc/kernel/ctx_sw.c25
-rw-r--r--arch/arc/kernel/ctx_sw_asm.S15
-rw-r--r--arch/arc/kernel/devtree.c101
-rw-r--r--arch/arc/kernel/disasm.c4
-rw-r--r--arch/arc/kernel/entry.S274
-rw-r--r--arch/arc/kernel/head.S83
-rw-r--r--arch/arc/kernel/irq.c68
-rw-r--r--arch/arc/kernel/kgdb.c17
-rw-r--r--arch/arc/kernel/kprobes.c14
-rw-r--r--arch/arc/kernel/module.c4
-rw-r--r--arch/arc/kernel/perf_event.c326
-rw-r--r--arch/arc/kernel/process.c59
-rw-r--r--arch/arc/kernel/ptrace.c20
-rw-r--r--arch/arc/kernel/reset.c1
-rw-r--r--arch/arc/kernel/setup.c92
-rw-r--r--arch/arc/kernel/signal.c25
-rw-r--r--arch/arc/kernel/smp.c155
-rw-r--r--arch/arc/kernel/stacktrace.c14
-rw-r--r--arch/arc/kernel/sys.c2
-rw-r--r--arch/arc/kernel/time.c74
-rw-r--r--arch/arc/kernel/traps.c75
-rw-r--r--arch/arc/kernel/troubleshoot.c84
-rw-r--r--arch/arc/kernel/unaligned.c34
-rw-r--r--arch/arc/kernel/unwind.c2
-rw-r--r--arch/arc/kernel/vmlinux.lds.S26
-rw-r--r--arch/arc/lib/memcmp.S6
-rw-r--r--arch/arc/lib/memcpy-700.S6
-rw-r--r--arch/arc/lib/memset.S10
-rw-r--r--arch/arc/lib/strchr-700.S16
-rw-r--r--arch/arc/lib/strcmp.S6
-rw-r--r--arch/arc/lib/strcpy-700.S6
-rw-r--r--arch/arc/lib/strlen.S6
-rw-r--r--arch/arc/mm/Makefile2
-rw-r--r--arch/arc/mm/cache_arc700.c676
-rw-r--r--arch/arc/mm/extable.c4
-rw-r--r--arch/arc/mm/fault.c36
-rw-r--r--arch/arc/mm/init.c97
-rw-r--r--arch/arc/mm/ioremap.c2
-rw-r--r--arch/arc/mm/mmap.c78
-rw-r--r--arch/arc/mm/tlb.c333
-rw-r--r--arch/arc/mm/tlbex.S244
-rw-r--r--arch/arc/plat-arcfpga/Kconfig33
-rw-r--r--arch/arc/plat-arcfpga/Makefile2
-rw-r--r--arch/arc/plat-arcfpga/include/plat/irq.h2
-rw-r--r--arch/arc/plat-arcfpga/include/plat/memmap.h2
-rw-r--r--arch/arc/plat-arcfpga/platform.c100
-rw-r--r--arch/arc/plat-arcfpga/smp.c30
-rw-r--r--arch/arc/plat-tb10x/Kconfig32
-rw-r--r--arch/arc/plat-tb10x/Makefile21
-rw-r--r--arch/arc/plat-tb10x/tb10x.c45
118 files changed, 4513 insertions, 2544 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index e6f4eca09ee..9596b0ab108 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -8,6 +8,7 @@
config ARC
def_bool y
+ select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
# ARC Busybox based initramfs absolutely relies on DEVTMPFS for /dev
select DEVTMPFS if !INITRAMFS_SOURCE=""
@@ -16,13 +17,10 @@ config ARC
select GENERIC_FIND_FIRST_BIT
# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
select GENERIC_IRQ_SHOW
- select GENERIC_KERNEL_EXECVE
- select GENERIC_KERNEL_THREAD
select GENERIC_PENDING_IRQ if SMP
select GENERIC_SMP_IDLE_THREAD
select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
- select HAVE_GENERIC_HARDIRQS
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
select HAVE_KRETPROBES
@@ -36,6 +34,13 @@ config ARC
select OF
select OF_EARLY_FLATTREE
select PERF_USE_VMALLOC
+ select HAVE_DEBUG_STACKOVERFLOW
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config LOCKDEP_SUPPORT
+ def_bool y
config SCHED_OMIT_FRAME_POINTER
def_bool y
@@ -52,7 +57,7 @@ config ARCH_FLATMEM_ENABLE
config MMU
def_bool y
-config NO_IOPORT
+config NO_IOPORT_MAP
def_bool y
config GENERIC_CALIBRATE_DELAY
@@ -61,9 +66,6 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_HWEIGHT
def_bool y
-config BINFMT_ELF
- def_bool y
-
config STACKTRACE_SUPPORT
def_bool y
select STACKTRACE
@@ -82,6 +84,7 @@ menu "ARC Architecture Configuration"
menu "ARC Platform/SoC/Board"
source "arch/arc/plat-arcfpga/Kconfig"
+source "arch/arc/plat-tb10x/Kconfig"
#New platform adds here
endmenu
@@ -123,31 +126,24 @@ config ARC_PLAT_NEEDS_CPU_TO_DMA
config SMP
bool "Symmetric Multi-Processing (Incomplete)"
default n
- select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
- a system with only one CPU, like most personal computers, say N. If
- you have a system with more than one CPU, say Y.
+ a system with only one CPU, say N. If you have a system with more
+ than one CPU, say Y.
if SMP
config ARC_HAS_COH_CACHES
def_bool n
-config ARC_HAS_COH_LLSC
- def_bool n
-
-config ARC_HAS_COH_RTSC
- def_bool n
-
config ARC_HAS_REENTRANT_IRQ_LV2
def_bool n
endif
config NR_CPUS
- int "Maximum number of CPUs (2-32)"
- range 2 32
+ int "Maximum number of CPUs (2-4096)"
+ range 2 4096
depends on SMP
default "2"
@@ -189,6 +185,11 @@ config ARC_CACHE_PAGES
Note that Global I/D ENABLE + Per Page DISABLE works but corollary
Global DISABLE + Per Page ENABLE won't work
+config ARC_CACHE_VIPT_ALIASING
+ bool "Support VIPT Aliasing D$"
+ depends on ARC_HAS_DCACHE
+ default n
+
endif #ARC_CACHE
config ARC_HAS_ICCM
@@ -304,6 +305,9 @@ config ARC_FPU_SAVE_RESTORE
based on actual usage of FPU by a task. Thus our implemn does
this for all tasks in system.
+config ARC_CANT_LLSC
+ def_bool n
+
menuconfig ARC_CPU_REL_4_10
bool "Enable support for Rel 4.10 features"
default n
@@ -314,9 +318,7 @@ menuconfig ARC_CPU_REL_4_10
config ARC_HAS_LLSC
bool "Insn: LLOCK/SCOND (efficient atomic ops)"
default y
- depends on ARC_CPU_770
- # if SMP, enable LLSC ONLY if ARC implementation has coherent atomics
- depends on !SMP || ARC_HAS_COH_LLSC
+ depends on ARC_CPU_770 && !ARC_CANT_LLSC
config ARC_HAS_SWAPE
bool "Insn: SWAPE (endian-swap)"
@@ -327,8 +329,7 @@ config ARC_HAS_RTSC
bool "Insn: RTSC (64-bit r/o cycle counter)"
default y
depends on ARC_CPU_REL_4_10
- # if SMP, enable RTSC only if counter is coherent across cores
- depends on !SMP || ARC_HAS_COH_RTSC
+ depends on !SMP
endmenu # "ARC CPU Configuration"
@@ -355,7 +356,6 @@ config ARC_CURR_IN_REG
config ARC_MISALIGN_ACCESS
bool "Emulate unaligned memory access (userspace only)"
- default N
select SYSCTL_ARCH_UNALIGN_NO_WARN
select SYSCTL_ARCH_UNALIGN_ALLOW
help
@@ -363,13 +363,6 @@ config ARC_MISALIGN_ACCESS
Use ONLY-IF-ABS-NECESSARY as it will be very slow and also can hide
potential bugs in code
-config ARC_STACK_NONEXEC
- bool "Make stack non-executable"
- default n
- help
- To disable the execute permissions of stack/heap of processes
- which are enabled by default.
-
config HZ
int "Timer Frequency"
default 100
@@ -415,24 +408,6 @@ config ARC_DBG_TLB_MISS_COUNT
Counts number of I and D TLB Misses and exports them via Debugfs
The counters can be cleared via Debugfs as well
-config CMDLINE
- string "Kernel command line to built-in"
- default "print-fatal-signals=1"
- help
- The default command line which will be appended to the optional
- u-boot provided command line (see below)
-
-config CMDLINE_UBOOT
- bool "Support U-boot kernel command line passing"
- default n
- help
- If you are using U-boot (www.denx.de) and wish to pass the kernel
- command line from the U-boot environment to the Linux kernel then
- switch this option on.
- ARC U-boot will setup the cmdline in RAM/flash and set r2 to point
- to it. kernel startup code will copy the string into cmdline buffer
- and also append CONFIG_CMDLINE.
-
config ARC_BUILTIN_DTB_NAME
string "Built in DTB"
help
@@ -441,6 +416,10 @@ config ARC_BUILTIN_DTB_NAME
source "kernel/Kconfig.preempt"
+menu "Executable file formats"
+source "fs/Kconfig.binfmt"
+endmenu
+
endmenu # "ARC Architecture Configuration"
source "mm/Kconfig"
diff --git a/arch/arc/Kconfig.debug b/arch/arc/Kconfig.debug
index 962c6099659..a7fc0da2565 100644
--- a/arch/arc/Kconfig.debug
+++ b/arch/arc/Kconfig.debug
@@ -15,13 +15,6 @@ config EARLY_PRINTK
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config 16KSTACKS
bool "Use 16Kb for kernel stacks instead of 8Kb"
help
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index 92379c7cbc1..8c0b1aa56f7 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -8,22 +8,28 @@
UTS_MACHINE := arc
+ifeq ($(CROSS_COMPILE),)
+CROSS_COMPILE := arc-linux-uclibc-
+endif
+
KBUILD_DEFCONFIG := fpga_defconfig
cflags-y += -mA7 -fno-common -pipe -fno-builtin -D__linux__
-LINUXINCLUDE += -include ${src}/arch/arc/include/asm/defines.h
-
ifdef CONFIG_ARC_CURR_IN_REG
# For a global register defintion, make sure it gets passed to every file
# We had a customer reported bug where some code built in kernel was NOT using
# any kernel headers, and missing the r25 global register
-# Can't do unconditionally (like above) because of recursive include issues
+# Can't do unconditionally because of recursive include issues
# due to <linux/thread_info.h>
LINUXINCLUDE += -include ${src}/arch/arc/include/asm/current.h
endif
-atleast_gcc44 := $(call cc-ifversion, -gt, 0402, y)
+upto_gcc42 := $(call cc-ifversion, -le, 0402, y)
+upto_gcc44 := $(call cc-ifversion, -le, 0404, y)
+atleast_gcc44 := $(call cc-ifversion, -ge, 0404, y)
+atleast_gcc48 := $(call cc-ifversion, -ge, 0408, y)
+
cflags-$(atleast_gcc44) += -fsection-anchors
cflags-$(CONFIG_ARC_HAS_LLSC) += -mlock
@@ -31,6 +37,11 @@ cflags-$(CONFIG_ARC_HAS_SWAPE) += -mswape
cflags-$(CONFIG_ARC_HAS_RTSC) += -mrtsc
cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables
+# By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok
+ifeq ($(atleast_gcc48),y)
+cflags-$(CONFIG_ARC_DW2_UNWIND) += -gdwarf-2
+endif
+
ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
# Generic build system uses -O2, we want -O3
cflags-y += -O3
@@ -44,11 +55,10 @@ cflags-$(disable_small_data) += -mno-sdata -fcall-used-gp
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mbig-endian
ldflags-$(CONFIG_CPU_BIG_ENDIAN) += -EB
-# STAR 9000518362:
+# STAR 9000518362: (fixed with binutils shipping with gcc 4.8)
# arc-linux-uclibc-ld (buildroot) or arceb-elf32-ld (EZChip) don't accept
-# --build-id w/o "-marclinux".
-# Default arc-elf32-ld is OK
-ldflags-y += -marclinux
+# --build-id w/o "-marclinux". Default arc-elf32-ld is OK
+ldflags-$(upto_gcc44) += -marclinux
ARC_LIBGCC := -mA7
cflags-$(CONFIG_ARC_HAS_HW_MPY) += -multcost=16
@@ -62,8 +72,8 @@ ifndef CONFIG_ARC_HAS_HW_MPY
# With gcc 4.4.7, -mno-mpy is enough to make any other related adjustments,
# e.g. increased cost of MPY. With gcc 4.2.1 this had to be explicitly hinted
- ARC_LIBGCC := -marc600
- ifneq ($(atleast_gcc44),y)
+ ifeq ($(upto_gcc42),y)
+ ARC_LIBGCC := -marc600
cflags-y += -multcost=30
endif
endif
@@ -87,20 +97,23 @@ core-y += arch/arc/
core-y += arch/arc/boot/dts/
core-$(CONFIG_ARC_PLAT_FPGA_LEGACY) += arch/arc/plat-arcfpga/
+core-$(CONFIG_ARC_PLAT_TB10X) += arch/arc/plat-tb10x/
drivers-$(CONFIG_OPROFILE) += arch/arc/oprofile/
libs-y += arch/arc/lib/ $(LIBGCC)
+boot := arch/arc/boot
+
#default target for make without any arguements.
-KBUILD_IMAGE := bootpImage
+KBUILD_IMAGE := bootpImage
all: $(KBUILD_IMAGE)
-boot := arch/arc/boot
-
bootpImage: vmlinux
-uImage: vmlinux
+boot_targets += uImage uImage.bin uImage.gz
+
+$(boot_targets): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
%.dtb %.dtb.S %.dtb.o: scripts
diff --git a/arch/arc/boot/.gitignore b/arch/arc/boot/.gitignore
new file mode 100644
index 00000000000..5246969a20c
--- /dev/null
+++ b/arch/arc/boot/.gitignore
@@ -0,0 +1,2 @@
+*.dtb*
+uImage
diff --git a/arch/arc/boot/Makefile b/arch/arc/boot/Makefile
index 7d514c24e09..e597cb34c16 100644
--- a/arch/arc/boot/Makefile
+++ b/arch/arc/boot/Makefile
@@ -3,7 +3,6 @@ targets := vmlinux.bin vmlinux.bin.gz uImage
# uImage build relies on mkimage being availble on your host for ARC target
# You will need to build u-boot for ARC, rename mkimage to arc-elf32-mkimage
# and make sure it's reacable from your PATH
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
OBJCOPYFLAGS= -O binary -R .note -R .note.gnu.build-id -R .comment -S
@@ -12,7 +11,12 @@ LINUX_START_TEXT = $$(readelf -h vmlinux | \
UIMAGE_LOADADDR = $(CONFIG_LINUX_LINK_BASE)
UIMAGE_ENTRYADDR = $(LINUX_START_TEXT)
-UIMAGE_COMPRESSION = gzip
+
+suffix-y := bin
+suffix-$(CONFIG_KERNEL_GZIP) := gz
+
+targets += uImage uImage.bin uImage.gz
+extra-y += vmlinux.bin vmlinux.bin.gz
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
@@ -20,7 +24,12 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
-$(obj)/uImage: $(obj)/vmlinux.bin.gz FORCE
- $(call if_changed,uimage)
+$(obj)/uImage.bin: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,uimage,none)
+
+$(obj)/uImage.gz: $(obj)/vmlinux.bin.gz FORCE
+ $(call if_changed,uimage,gzip)
-PHONY += FORCE
+$(obj)/uImage: $(obj)/uImage.$(suffix-y)
+ @ln -sf $(notdir $<) $@
+ @echo ' Image $@ is ready'
diff --git a/arch/arc/boot/dts/Makefile b/arch/arc/boot/dts/Makefile
index 5776835d583..faf240e29ec 100644
--- a/arch/arc/boot/dts/Makefile
+++ b/arch/arc/boot/dts/Makefile
@@ -8,6 +8,8 @@ endif
obj-y += $(builtindtb-y).dtb.o
targets += $(builtindtb-y).dtb
+.SECONDARY: $(obj)/$(builtindtb-y).dtb.S
+
dtbs: $(addprefix $(obj)/, $(builtindtb-y).dtb)
-clean-files := *.dtb
+clean-files := *.dtb *.dtb.S
diff --git a/arch/arc/boot/dts/abilis_tb100.dtsi b/arch/arc/boot/dts/abilis_tb100.dtsi
new file mode 100644
index 00000000000..3942634f805
--- /dev/null
+++ b/arch/arc/boot/dts/abilis_tb100.dtsi
@@ -0,0 +1,350 @@
+/*
+ * Abilis Systems TB100 SOC device tree
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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/ "abilis_tb10x.dtsi"
+
+
+/ {
+ clock-frequency = <500000000>; /* 500 MHZ */
+
+ soc100 {
+ bus-frequency = <166666666>;
+
+ pll0: oscillator {
+ clock-frequency = <1000000000>;
+ };
+ cpu_clk: clkdiv_cpu {
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+ ahb_clk: clkdiv_ahb {
+ clock-mult = <1>;
+ clock-div = <6>;
+ };
+
+ iomux: iomux@FF10601c {
+ /* Port 1 */
+ pctl_tsin_s0: pctl-tsin-s0 { /* Serial TS-in 0 */
+ abilis,function = "mis0";
+ };
+ pctl_tsin_s1: pctl-tsin-s1 { /* Serial TS-in 1 */
+ abilis,function = "mis1";
+ };
+ pctl_gpio_a: pctl-gpio-a { /* GPIO bank A */
+ abilis,function = "gpioa";
+ };
+ pctl_tsin_p1: pctl-tsin-p1 { /* Parallel TS-in 1 */
+ abilis,function = "mip1";
+ };
+ /* Port 2 */
+ pctl_tsin_s2: pctl-tsin-s2 { /* Serial TS-in 2 */
+ abilis,function = "mis2";
+ };
+ pctl_tsin_s3: pctl-tsin-s3 { /* Serial TS-in 3 */
+ abilis,function = "mis3";
+ };
+ pctl_gpio_c: pctl-gpio-c { /* GPIO bank C */
+ abilis,function = "gpioc";
+ };
+ pctl_tsin_p3: pctl-tsin-p3 { /* Parallel TS-in 3 */
+ abilis,function = "mip3";
+ };
+ /* Port 3 */
+ pctl_tsin_s4: pctl-tsin-s4 { /* Serial TS-in 4 */
+ abilis,function = "mis4";
+ };
+ pctl_tsin_s5: pctl-tsin-s5 { /* Serial TS-in 5 */
+ abilis,function = "mis5";
+ };
+ pctl_gpio_e: pctl-gpio-e { /* GPIO bank E */
+ abilis,function = "gpioe";
+ };
+ pctl_tsin_p5: pctl-tsin-p5 { /* Parallel TS-in 5 */
+ abilis,function = "mip5";
+ };
+ /* Port 4 */
+ pctl_tsin_s6: pctl-tsin-s6 { /* Serial TS-in 6 */
+ abilis,function = "mis6";
+ };
+ pctl_tsin_s7: pctl-tsin-s7 { /* Serial TS-in 7 */
+ abilis,function = "mis7";
+ };
+ pctl_gpio_g: pctl-gpio-g { /* GPIO bank G */
+ abilis,function = "gpiog";
+ };
+ pctl_tsin_p7: pctl-tsin-p7 { /* Parallel TS-in 7 */
+ abilis,function = "mip7";
+ };
+ /* Port 5 */
+ pctl_gpio_j: pctl-gpio-j { /* GPIO bank J */
+ abilis,function = "gpioj";
+ };
+ pctl_gpio_k: pctl-gpio-k { /* GPIO bank K */
+ abilis,function = "gpiok";
+ };
+ pctl_ciplus: pctl-ciplus { /* CI+ interface */
+ abilis,function = "ciplus";
+ };
+ pctl_mcard: pctl-mcard { /* M-Card interface */
+ abilis,function = "mcard";
+ };
+ /* Port 6 */
+ pctl_tsout_p: pctl-tsout-p { /* Parallel TS-out */
+ abilis,function = "mop";
+ };
+ pctl_tsout_s0: pctl-tsout-s0 { /* Serial TS-out 0 */
+ abilis,function = "mos0";
+ };
+ pctl_tsout_s1: pctl-tsout-s1 { /* Serial TS-out 1 */
+ abilis,function = "mos1";
+ };
+ pctl_tsout_s2: pctl-tsout-s2 { /* Serial TS-out 2 */
+ abilis,function = "mos2";
+ };
+ pctl_tsout_s3: pctl-tsout-s3 { /* Serial TS-out 3 */
+ abilis,function = "mos3";
+ };
+ /* Port 7 */
+ pctl_uart0: pctl-uart0 { /* UART 0 */
+ abilis,function = "uart0";
+ };
+ pctl_uart1: pctl-uart1 { /* UART 1 */
+ abilis,function = "uart1";
+ };
+ pctl_gpio_l: pctl-gpio-l { /* GPIO bank L */
+ abilis,function = "gpiol";
+ };
+ pctl_gpio_m: pctl-gpio-m { /* GPIO bank M */
+ abilis,function = "gpiom";
+ };
+ /* Port 8 */
+ pctl_spi3: pctl-spi3 {
+ abilis,function = "spi3";
+ };
+ /* Port 9 */
+ pctl_spi1: pctl-spi1 {
+ abilis,function = "spi1";
+ };
+ pctl_gpio_n: pctl-gpio-n {
+ abilis,function = "gpion";
+ };
+ /* Unmuxed GPIOs */
+ pctl_gpio_b: pctl-gpio-b {
+ abilis,function = "gpiob";
+ };
+ pctl_gpio_d: pctl-gpio-d {
+ abilis,function = "gpiod";
+ };
+ pctl_gpio_f: pctl-gpio-f {
+ abilis,function = "gpiof";
+ };
+ pctl_gpio_h: pctl-gpio-h {
+ abilis,function = "gpioh";
+ };
+ pctl_gpio_i: pctl-gpio-i {
+ abilis,function = "gpioi";
+ };
+ };
+
+ gpioa: gpio@FF140000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF140000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioa";
+ };
+ gpiob: gpio@FF141000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF141000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiob";
+ };
+ gpioc: gpio@FF142000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF142000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioc";
+ };
+ gpiod: gpio@FF143000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF143000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiod";
+ };
+ gpioe: gpio@FF144000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF144000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioe";
+ };
+ gpiof: gpio@FF145000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF145000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiof";
+ };
+ gpiog: gpio@FF146000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF146000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiog";
+ };
+ gpioh: gpio@FF147000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF147000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioh";
+ };
+ gpioi: gpio@FF148000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF148000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <12>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioi";
+ };
+ gpioj: gpio@FF149000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF149000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <32>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioj";
+ };
+ gpiok: gpio@FF14a000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14A000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <22>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiok";
+ };
+ gpiol: gpio@FF14b000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14B000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <4>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiol";
+ };
+ gpiom: gpio@FF14c000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14C000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <4>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiom";
+ };
+ gpion: gpio@FF14d000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14D000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <5>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpion";
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/abilis_tb100_dvk.dts b/arch/arc/boot/dts/abilis_tb100_dvk.dts
new file mode 100644
index 00000000000..3dd6ed94146
--- /dev/null
+++ b/arch/arc/boot/dts/abilis_tb100_dvk.dts
@@ -0,0 +1,127 @@
+/*
+ * Abilis Systems TB100 Development Kit PCB device tree
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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
+ */
+
+/dts-v1/;
+
+/include/ "abilis_tb100.dtsi"
+
+/ {
+ chosen {
+ bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
+ };
+
+ aliases { };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x08000000>; /* 128M */
+ };
+
+ soc100 {
+ uart@FF100000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pctl_uart0>;
+ };
+ ethernet@FE100000 {
+ phy-mode = "rgmii";
+ };
+
+ i2c0: i2c@FF120000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c1: i2c@FF121000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c2: i2c@FF122000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c3: i2c@FF123000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c4: i2c@FF124000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ power {
+ label = "Power";
+ gpios = <&gpioi 0 0>;
+ linux,default-trigger = "default-on";
+ };
+ heartbeat {
+ label = "Heartbeat";
+ gpios = <&gpioi 1 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ led2 {
+ label = "LED2";
+ gpios = <&gpioi 2 0>;
+ default-state = "off";
+ };
+ led3 {
+ label = "LED3";
+ gpios = <&gpioi 3 0>;
+ default-state = "off";
+ };
+ led4 {
+ label = "LED4";
+ gpios = <&gpioi 4 0>;
+ default-state = "off";
+ };
+ led5 {
+ label = "LED5";
+ gpios = <&gpioi 5 0>;
+ default-state = "off";
+ };
+ led6 {
+ label = "LED6";
+ gpios = <&gpioi 6 0>;
+ default-state = "off";
+ };
+ led7 {
+ label = "LED7";
+ gpios = <&gpioi 7 0>;
+ default-state = "off";
+ };
+ led8 {
+ label = "LED8";
+ gpios = <&gpioi 8 0>;
+ default-state = "off";
+ };
+ led9 {
+ label = "LED9";
+ gpios = <&gpioi 9 0>;
+ default-state = "off";
+ };
+ led10 {
+ label = "LED10";
+ gpios = <&gpioi 10 0>;
+ default-state = "off";
+ };
+ led11 {
+ label = "LED11";
+ gpios = <&gpioi 11 0>;
+ default-state = "off";
+ };
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/abilis_tb101.dtsi b/arch/arc/boot/dts/abilis_tb101.dtsi
new file mode 100644
index 00000000000..b0467229a5c
--- /dev/null
+++ b/arch/arc/boot/dts/abilis_tb101.dtsi
@@ -0,0 +1,359 @@
+/*
+ * Abilis Systems TB101 SOC device tree
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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/ "abilis_tb10x.dtsi"
+
+
+/ {
+ clock-frequency = <500000000>; /* 500 MHZ */
+
+ soc100 {
+ bus-frequency = <166666666>;
+
+ pll0: oscillator {
+ clock-frequency = <1000000000>;
+ };
+ cpu_clk: clkdiv_cpu {
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+ ahb_clk: clkdiv_ahb {
+ clock-mult = <1>;
+ clock-div = <6>;
+ };
+
+ iomux: iomux@FF10601c {
+ /* Port 1 */
+ pctl_tsin_s0: pctl-tsin-s0 { /* Serial TS-in 0 */
+ abilis,function = "mis0";
+ };
+ pctl_tsin_s1: pctl-tsin-s1 { /* Serial TS-in 1 */
+ abilis,function = "mis1";
+ };
+ pctl_gpio_a: pctl-gpio-a { /* GPIO bank A */
+ abilis,function = "gpioa";
+ };
+ pctl_tsin_p1: pctl-tsin-p1 { /* Parallel TS-in 1 */
+ abilis,function = "mip1";
+ };
+ /* Port 2 */
+ pctl_tsin_s2: pctl-tsin-s2 { /* Serial TS-in 2 */
+ abilis,function = "mis2";
+ };
+ pctl_tsin_s3: pctl-tsin-s3 { /* Serial TS-in 3 */
+ abilis,function = "mis3";
+ };
+ pctl_gpio_c: pctl-gpio-c { /* GPIO bank C */
+ abilis,function = "gpioc";
+ };
+ pctl_tsin_p3: pctl-tsin-p3 { /* Parallel TS-in 3 */
+ abilis,function = "mip3";
+ };
+ /* Port 3 */
+ pctl_tsin_s4: pctl-tsin-s4 { /* Serial TS-in 4 */
+ abilis,function = "mis4";
+ };
+ pctl_tsin_s5: pctl-tsin-s5 { /* Serial TS-in 5 */
+ abilis,function = "mis5";
+ };
+ pctl_gpio_e: pctl-gpio-e { /* GPIO bank E */
+ abilis,function = "gpioe";
+ };
+ pctl_tsin_p5: pctl-tsin-p5 { /* Parallel TS-in 5 */
+ abilis,function = "mip5";
+ };
+ /* Port 4 */
+ pctl_tsin_s6: pctl-tsin-s6 { /* Serial TS-in 6 */
+ abilis,function = "mis6";
+ };
+ pctl_tsin_s7: pctl-tsin-s7 { /* Serial TS-in 7 */
+ abilis,function = "mis7";
+ };
+ pctl_gpio_g: pctl-gpio-g { /* GPIO bank G */
+ abilis,function = "gpiog";
+ };
+ pctl_tsin_p7: pctl-tsin-p7 { /* Parallel TS-in 7 */
+ abilis,function = "mip7";
+ };
+ /* Port 5 */
+ pctl_gpio_j: pctl-gpio-j { /* GPIO bank J */
+ abilis,function = "gpioj";
+ };
+ pctl_gpio_k: pctl-gpio-k { /* GPIO bank K */
+ abilis,function = "gpiok";
+ };
+ pctl_ciplus: pctl-ciplus { /* CI+ interface */
+ abilis,function = "ciplus";
+ };
+ pctl_mcard: pctl-mcard { /* M-Card interface */
+ abilis,function = "mcard";
+ };
+ pctl_stc0: pctl-stc0 { /* Smart card I/F 0 */
+ abilis,function = "stc0";
+ };
+ pctl_stc1: pctl-stc1 { /* Smart card I/F 1 */
+ abilis,function = "stc1";
+ };
+ /* Port 6 */
+ pctl_tsout_p: pctl-tsout-p { /* Parallel TS-out */
+ abilis,function = "mop";
+ };
+ pctl_tsout_s0: pctl-tsout-s0 { /* Serial TS-out 0 */
+ abilis,function = "mos0";
+ };
+ pctl_tsout_s1: pctl-tsout-s1 { /* Serial TS-out 1 */
+ abilis,function = "mos1";
+ };
+ pctl_tsout_s2: pctl-tsout-s2 { /* Serial TS-out 2 */
+ abilis,function = "mos2";
+ };
+ pctl_tsout_s3: pctl-tsout-s3 { /* Serial TS-out 3 */
+ abilis,function = "mos3";
+ };
+ /* Port 7 */
+ pctl_uart0: pctl-uart0 { /* UART 0 */
+ abilis,function = "uart0";
+ };
+ pctl_uart1: pctl-uart1 { /* UART 1 */
+ abilis,function = "uart1";
+ };
+ pctl_gpio_l: pctl-gpio-l { /* GPIO bank L */
+ abilis,function = "gpiol";
+ };
+ pctl_gpio_m: pctl-gpio-m { /* GPIO bank M */
+ abilis,function = "gpiom";
+ };
+ /* Port 8 */
+ pctl_spi3: pctl-spi3 {
+ abilis,function = "spi3";
+ };
+ pctl_jtag: pctl-jtag {
+ abilis,function = "jtag";
+ };
+ /* Port 9 */
+ pctl_spi1: pctl-spi1 {
+ abilis,function = "spi1";
+ };
+ pctl_gpio_n: pctl-gpio-n {
+ abilis,function = "gpion";
+ };
+ /* Unmuxed GPIOs */
+ pctl_gpio_b: pctl-gpio-b {
+ abilis,function = "gpiob";
+ };
+ pctl_gpio_d: pctl-gpio-d {
+ abilis,function = "gpiod";
+ };
+ pctl_gpio_f: pctl-gpio-f {
+ abilis,function = "gpiof";
+ };
+ pctl_gpio_h: pctl-gpio-h {
+ abilis,function = "gpioh";
+ };
+ pctl_gpio_i: pctl-gpio-i {
+ abilis,function = "gpioi";
+ };
+ };
+
+ gpioa: gpio@FF140000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF140000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioa";
+ };
+ gpiob: gpio@FF141000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF141000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiob";
+ };
+ gpioc: gpio@FF142000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF142000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioc";
+ };
+ gpiod: gpio@FF143000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF143000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiod";
+ };
+ gpioe: gpio@FF144000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF144000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioe";
+ };
+ gpiof: gpio@FF145000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF145000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiof";
+ };
+ gpiog: gpio@FF146000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF146000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <3>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiog";
+ };
+ gpioh: gpio@FF147000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF147000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <2>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioh";
+ };
+ gpioi: gpio@FF148000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF148000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <12>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioi";
+ };
+ gpioj: gpio@FF149000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF149000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <32>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpioj";
+ };
+ gpiok: gpio@FF14a000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14A000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <22>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiok";
+ };
+ gpiol: gpio@FF14b000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14B000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <4>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiol";
+ };
+ gpiom: gpio@FF14c000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14C000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <4>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpiom";
+ };
+ gpion: gpio@FF14d000 {
+ compatible = "abilis,tb10x-gpio";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <27 2>;
+ reg = <0xFF14D000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ abilis,ngpio = <5>;
+ gpio-ranges = <&iomux 0 0 0>;
+ gpio-ranges-group-names = "gpion";
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/abilis_tb101_dvk.dts b/arch/arc/boot/dts/abilis_tb101_dvk.dts
new file mode 100644
index 00000000000..1cf51c280f2
--- /dev/null
+++ b/arch/arc/boot/dts/abilis_tb101_dvk.dts
@@ -0,0 +1,127 @@
+/*
+ * Abilis Systems TB101 Development Kit PCB device tree
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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
+ */
+
+/dts-v1/;
+
+/include/ "abilis_tb101.dtsi"
+
+/ {
+ chosen {
+ bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
+ };
+
+ aliases { };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x08000000>; /* 128M */
+ };
+
+ soc100 {
+ uart@FF100000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pctl_uart0>;
+ };
+ ethernet@FE100000 {
+ phy-mode = "rgmii";
+ };
+
+ i2c0: i2c@FF120000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c1: i2c@FF121000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c2: i2c@FF122000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c3: i2c@FF123000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+ i2c4: i2c@FF124000 {
+ i2c-sda-hold-time-ns = <432>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ power {
+ label = "Power";
+ gpios = <&gpioi 0 0>;
+ linux,default-trigger = "default-on";
+ };
+ heartbeat {
+ label = "Heartbeat";
+ gpios = <&gpioi 1 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ led2 {
+ label = "LED2";
+ gpios = <&gpioi 2 0>;
+ default-state = "off";
+ };
+ led3 {
+ label = "LED3";
+ gpios = <&gpioi 3 0>;
+ default-state = "off";
+ };
+ led4 {
+ label = "LED4";
+ gpios = <&gpioi 4 0>;
+ default-state = "off";
+ };
+ led5 {
+ label = "LED5";
+ gpios = <&gpioi 5 0>;
+ default-state = "off";
+ };
+ led6 {
+ label = "LED6";
+ gpios = <&gpioi 6 0>;
+ default-state = "off";
+ };
+ led7 {
+ label = "LED7";
+ gpios = <&gpioi 7 0>;
+ default-state = "off";
+ };
+ led8 {
+ label = "LED8";
+ gpios = <&gpioi 8 0>;
+ default-state = "off";
+ };
+ led9 {
+ label = "LED9";
+ gpios = <&gpioi 9 0>;
+ default-state = "off";
+ };
+ led10 {
+ label = "LED10";
+ gpios = <&gpioi 10 0>;
+ default-state = "off";
+ };
+ led11 {
+ label = "LED11";
+ gpios = <&gpioi 11 0>;
+ default-state = "off";
+ };
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi
new file mode 100644
index 00000000000..a098d7c05e9
--- /dev/null
+++ b/arch/arc/boot/dts/abilis_tb10x.dtsi
@@ -0,0 +1,240 @@
+/*
+ * Abilis Systems TB10X SOC device tree
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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
+ */
+
+
+/ {
+ compatible = "abilis,arc-tb10x";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "snps,arc770d";
+ reg = <0>;
+ };
+ };
+
+ soc100 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ ranges = <0xfe000000 0xfe000000 0x02000000
+ 0x000F0000 0x000F0000 0x00010000>;
+ compatible = "abilis,tb10x", "simple-bus";
+
+ pll0: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-output-names = "pll0";
+ };
+ cpu_clk: clkdiv_cpu {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clocks = <&pll0>;
+ clock-output-names = "cpu_clk";
+ };
+ ahb_clk: clkdiv_ahb {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clocks = <&pll0>;
+ clock-output-names = "ahb_clk";
+ };
+
+ iomux: iomux@FF10601c {
+ compatible = "abilis,tb10x-iomux";
+ #gpio-range-cells = <3>;
+ reg = <0xFF10601c 0x4>;
+ };
+
+ intc: interrupt-controller {
+ compatible = "snps,arc700-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ tb10x_ictl: pic@fe002000 {
+ compatible = "abilis,tb10x-ictl";
+ reg = <0xFE002000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+ };
+
+ uart@FF100000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xFF100000 0x100>;
+ clock-frequency = <166666666>;
+ interrupts = <25 8>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupt-parent = <&tb10x_ictl>;
+ };
+ ethernet@FE100000 {
+ compatible = "snps,dwmac-3.70a","snps,dwmac";
+ reg = <0xFE100000 0x1058>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <6 8>;
+ interrupt-names = "macirq";
+ clocks = <&ahb_clk>;
+ clock-names = "stmmaceth";
+ };
+ dma@FE000000 {
+ compatible = "snps,dma-spear1340";
+ reg = <0xFE000000 0x400>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <14 8>;
+ dma-channels = <6>;
+ dma-requests = <0>;
+ dma-masters = <1>;
+ #dma-cells = <3>;
+ chan_allocation_order = <0>;
+ chan_priority = <1>;
+ block_size = <0x7ff>;
+ data_width = <2 0 0 0>;
+ clocks = <&ahb_clk>;
+ clock-names = "hclk";
+ };
+
+ i2c0: i2c@FF120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xFF120000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <12 8>;
+ clocks = <&ahb_clk>;
+ };
+ i2c1: i2c@FF121000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xFF121000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <12 8>;
+ clocks = <&ahb_clk>;
+ };
+ i2c2: i2c@FF122000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xFF122000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <12 8>;
+ clocks = <&ahb_clk>;
+ };
+ i2c3: i2c@FF123000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xFF123000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <12 8>;
+ clocks = <&ahb_clk>;
+ };
+ i2c4: i2c@FF124000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xFF124000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <12 8>;
+ clocks = <&ahb_clk>;
+ };
+
+ spi0: spi@0xFE010000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "abilis,tb100-spi";
+ num-cs = <1>;
+ reg = <0xFE010000 0x20>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <26 8>;
+ clocks = <&ahb_clk>;
+ };
+ spi1: spi@0xFE011000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "abilis,tb100-spi";
+ num-cs = <2>;
+ reg = <0xFE011000 0x20>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <10 8>;
+ clocks = <&ahb_clk>;
+ };
+
+ tb10x_tsm: tb10x-tsm@ff316000 {
+ compatible = "abilis,tb100-tsm";
+ reg = <0xff316000 0x400>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <17 8>;
+ output-clkdiv = <4>;
+ global-packet-delay = <0x21>;
+ port-packet-delay = <0>;
+ };
+ tb10x_stream_proc: tb10x-stream-proc {
+ compatible = "abilis,tb100-streamproc";
+ reg = <0xfff00000 0x200>,
+ <0x000f0000 0x10000>,
+ <0xfff00200 0x105>,
+ <0xff10600c 0x1>,
+ <0xfe001018 0x1>;
+ reg-names = "mbox",
+ "sp_iccm",
+ "mbox_irq",
+ "cpuctrl",
+ "a6it_int_force";
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <20 2>, <19 2>;
+ interrupt-names = "cmd_irq", "event_irq";
+ };
+ tb10x_mdsc0: tb10x-mdscr@FF300000 {
+ compatible = "abilis,tb100-mdscr";
+ reg = <0xFF300000 0x7000>;
+ tb100-mdscr-manage-tsin;
+ };
+ tb10x_mscr0: tb10x-mdscr@FF307000 {
+ compatible = "abilis,tb100-mdscr";
+ reg = <0xFF307000 0x7000>;
+ };
+ tb10x_scr0: tb10x-mdscr@ff30e000 {
+ compatible = "abilis,tb100-mdscr";
+ reg = <0xFF30e000 0x4000>;
+ tb100-mdscr-manage-tsin;
+ };
+ tb10x_scr1: tb10x-mdscr@ff312000 {
+ compatible = "abilis,tb100-mdscr";
+ reg = <0xFF312000 0x4000>;
+ tb100-mdscr-manage-tsin;
+ };
+ tb10x_wfb: tb10x-wfb@ff319000 {
+ compatible = "abilis,tb100-wfb";
+ reg = <0xff319000 0x1000>;
+ interrupt-parent = <&tb10x_ictl>;
+ interrupts = <16 8>;
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/angel4.dts b/arch/arc/boot/dts/angel4.dts
index bae4f936cb0..5bb2fdaca02 100644
--- a/arch/arc/boot/dts/angel4.dts
+++ b/arch/arc/boot/dts/angel4.dts
@@ -17,7 +17,7 @@
interrupt-parent = <&intc>;
chosen {
- bootargs = "console=ttyARC0,115200n8";
+ bootargs = "console=ttyARC0,115200n8 earlyprintk=ttyARC0";
};
aliases {
@@ -51,5 +51,25 @@
current-speed = <115200>;
status = "okay";
};
+
+ ethernet@c0fc2000 {
+ compatible = "snps,arc-emac";
+ reg = <0xc0fc2000 0x3c>;
+ interrupts = <6>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ clock-frequency = <80000000>;
+ max-speed = <100>;
+ phy = <&phy0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: ethernet-phy@0 {
+ reg = <1>;
+ };
+ };
+
+ arcpmu0: pmu {
+ compatible = "snps,arc700-pmu";
+ };
};
};
diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts
new file mode 100644
index 00000000000..4f31b2eb5cd
--- /dev/null
+++ b/arch/arc/boot/dts/nsimosci.dts
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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.
+ */
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "snps,nsimosci";
+ clock-frequency = <20000000>; /* 20 MHZ */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ chosen {
+ /* this is for console on PGU */
+ /* bootargs = "console=tty0 consoleblank=0"; */
+ /* this is for console on serial */
+ bootargs = "earlycon=uart8250,mmio32,0xc0000000,115200n8 console=ttyS0,115200n8 consoleblank=0 debug";
+ };
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x10000000>; /* 256M */
+ };
+
+ fpga {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* child and parent address space 1:1 mapped */
+ ranges;
+
+ intc: interrupt-controller {
+ compatible = "snps,arc700-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ uart0: serial@c0000000 {
+ compatible = "ns8250";
+ reg = <0xc0000000 0x2000>;
+ interrupts = <11>;
+ clock-frequency = <3686400>;
+ baud = <115200>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ no-loopback-test = <1>;
+ };
+
+ pgu0: pgu@c9000000 {
+ compatible = "snps,arcpgufb";
+ reg = <0xc9000000 0x400>;
+ };
+
+ ps2: ps2@c9001000 {
+ compatible = "snps,arc_ps2";
+ reg = <0xc9000400 0x14>;
+ interrupts = <13>;
+ interrupt-names = "arc_ps2_irq";
+ };
+
+ eth0: ethernet@c0003000 {
+ compatible = "snps,oscilan";
+ reg = <0xc0003000 0x44>;
+ interrupts = <7>, <8>;
+ interrupt-names = "rx", "tx";
+ };
+ };
+};
diff --git a/arch/arc/boot/dts/skeleton.dts b/arch/arc/boot/dts/skeleton.dts
deleted file mode 100644
index 25a84fb5b3d..00000000000
--- a/arch/arc/boot/dts/skeleton.dts
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
- *
- * 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.
- */
-/dts-v1/;
-
-/include/ "skeleton.dtsi"
diff --git a/arch/arc/configs/fpga_defconfig b/arch/arc/configs/fpga_defconfig
index b8698067ebb..e283aa58693 100644
--- a/arch/arc/configs/fpga_defconfig
+++ b/arch/arc/configs/fpga_defconfig
@@ -1,7 +1,9 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -9,7 +11,7 @@ CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../arc_initramfs"
+CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
# CONFIG_SLUB_DEBUG is not set
@@ -24,6 +26,7 @@ CONFIG_ARC_PLAT_FPGA_LEGACY=y
CONFIG_ARC_BOARD_ML509=y
# CONFIG_ARC_HAS_RTSC is not set
CONFIG_ARC_BUILTIN_DTB_NAME="angel4"
+CONFIG_PREEMPT=y
# CONFIG_COMPACTION is not set
# CONFIG_CROSS_MEMORY_ATTACH is not set
CONFIG_NET=y
@@ -37,6 +40,9 @@ CONFIG_INET=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FIRMWARE_IN_KERNEL is not set
# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+CONFIG_ARC_EMAC=y
+CONFIG_LXT_PHY=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
@@ -58,4 +64,5 @@ CONFIG_TMPFS=y
CONFIG_NFS_FS=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_DEBUG_PREEMPT is not set
CONFIG_XZ_DEC=y
diff --git a/arch/arc/configs/fpga_noramfs_defconfig b/arch/arc/configs/fpga_noramfs_defconfig
new file mode 100644
index 00000000000..5276a52f6a2
--- /dev/null
+++ b/arch/arc/configs/fpga_noramfs_defconfig
@@ -0,0 +1,64 @@
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="ARCLinux"
+# CONFIG_SWAP is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARC_PLAT_FPGA_LEGACY=y
+CONFIG_ARC_BOARD_ML509=y
+# CONFIG_ARC_HAS_RTSC is not set
+CONFIG_ARC_BUILTIN_DTB_NAME="angel4"
+CONFIG_PREEMPT=y
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+CONFIG_ARC_EMAC=y
+CONFIG_LXT_PHY=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_ARC=y
+CONFIG_SERIAL_ARC_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_XZ_DEC=y
diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig
new file mode 100644
index 00000000000..c01ba35a4ef
--- /dev/null
+++ b/arch/arc/configs/nsimosci_defconfig
@@ -0,0 +1,76 @@
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="ARCLinux"
+# CONFIG_SWAP is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="../arc_initramfs"
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARC_PLAT_FPGA_LEGACY=y
+CONFIG_ARC_BOARD_ML509=y
+# CONFIG_ARC_IDE is not set
+# CONFIG_ARCTANGENT_EMAC is not set
+# CONFIG_ARC_HAS_RTSC is not set
+CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci"
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_SYNAPTICS is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+CONFIG_MOUSE_PS2_TOUCHKIT=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_ARC_PS2=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_ARC=y
+CONFIG_SERIAL_ARC_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_XZ_DEC=y
diff --git a/arch/arc/configs/tb10x_defconfig b/arch/arc/configs/tb10x_defconfig
new file mode 100644
index 00000000000..6be6492442d
--- /dev/null
+++ b/arch/arc/configs/tb10x_defconfig
@@ -0,0 +1,117 @@
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="tb10x"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="../tb10x-rootfs.cpio"
+CONFIG_INITRAMFS_ROOT_UID=2100
+CONFIG_INITRAMFS_ROOT_GID=501
+# CONFIG_RD_GZIP is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLOCK is not set
+CONFIG_ARC_PLAT_TB10X=y
+CONFIG_ARC_CACHE_LINE_SHIFT=5
+# CONFIG_ARC_HAS_RTSC is not set
+CONFIG_ARC_STACK_NONEXEC=y
+CONFIG_HZ=250
+CONFIG_ARC_BUILTIN_DTB_NAME="abilis_tb100_dvk"
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_PROC_DEVICETREE=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_DEBUG_FS=y
+CONFIG_STMMAC_DA=y
+CONFIG_STMMAC_CHAINED=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_8250_DW=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=y
+CONFIG_DMADEVICES=y
+CONFIG_DW_DMAC=y
+CONFIG_NET_DMA=y
+CONFIG_ASYNC_TX_DMA=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index 48af742f8b5..e76fd79f32b 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -1,16 +1,18 @@
generic-y += auxvec.h
-generic-y += bugs.h
+generic-y += barrier.h
generic-y += bitsperlong.h
+generic-y += bugs.h
generic-y += clkdev.h
generic-y += cputime.h
generic-y += device.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
-generic-y += fcntl.h
generic-y += fb.h
+generic-y += fcntl.h
generic-y += ftrace.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -20,6 +22,7 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += param.h
@@ -28,11 +31,11 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
generic-y += shmbuf.h
-generic-y += shmparam.h
generic-y += siginfo.h
generic-y += socket.h
generic-y += sockios.h
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index 1b907c46566..355cb470c2a 100644
--- a/arch/arc/include/asm/arcregs.h
+++ b/arch/arc/include/asm/arcregs.h
@@ -20,7 +20,6 @@
#define ARC_REG_PERIBASE_BCR 0x69
#define ARC_REG_FP_BCR 0x6B /* Single-Precision FPU */
#define ARC_REG_DPFP_BCR 0x6C /* Dbl Precision FPU */
-#define ARC_REG_MMU_BCR 0x6f
#define ARC_REG_DCCM_BCR 0x74 /* DCCM Present + SZ */
#define ARC_REG_TIMERS_BCR 0x75
#define ARC_REG_ICCM_BCR 0x78
@@ -34,22 +33,12 @@
#define ARC_REG_D_UNCACH_BCR 0x6A
/* status32 Bits Positions */
-#define STATUS_H_BIT 0 /* CPU Halted */
-#define STATUS_E1_BIT 1 /* Int 1 enable */
-#define STATUS_E2_BIT 2 /* Int 2 enable */
-#define STATUS_A1_BIT 3 /* Int 1 active */
-#define STATUS_A2_BIT 4 /* Int 2 active */
#define STATUS_AE_BIT 5 /* Exception active */
#define STATUS_DE_BIT 6 /* PC is in delay slot */
#define STATUS_U_BIT 7 /* User/Kernel mode */
#define STATUS_L_BIT 12 /* Loop inhibit */
/* These masks correspond to the status word(STATUS_32) bits */
-#define STATUS_H_MASK (1<<STATUS_H_BIT)
-#define STATUS_E1_MASK (1<<STATUS_E1_BIT)
-#define STATUS_E2_MASK (1<<STATUS_E2_BIT)
-#define STATUS_A1_MASK (1<<STATUS_A1_BIT)
-#define STATUS_A2_MASK (1<<STATUS_A2_BIT)
#define STATUS_AE_MASK (1<<STATUS_AE_BIT)
#define STATUS_DE_MASK (1<<STATUS_DE_BIT)
#define STATUS_U_MASK (1<<STATUS_U_BIT)
@@ -71,6 +60,7 @@
#define ECR_V_ITLB_MISS 0x21
#define ECR_V_DTLB_MISS 0x22
#define ECR_V_PROTV 0x23
+#define ECR_V_TRAP 0x25
/* Protection Violation Exception Cause Code Values */
#define ECR_C_PROTV_INST_FETCH 0x00
@@ -79,94 +69,23 @@
#define ECR_C_PROTV_XCHG 0x03
#define ECR_C_PROTV_MISALIG_DATA 0x04
+#define ECR_C_BIT_PROTV_MISALIG_DATA 10
+
+/* Machine Check Cause Code Values */
+#define ECR_C_MCHK_DUP_TLB 0x01
+
/* DTLB Miss Exception Cause Code Values */
#define ECR_C_BIT_DTLB_LD_MISS 8
#define ECR_C_BIT_DTLB_ST_MISS 9
+/* Dummy ECR values for Interrupts */
+#define event_IRQ1 0x0031abcd
+#define event_IRQ2 0x0032abcd
/* Auxiliary registers */
#define AUX_IDENTITY 4
#define AUX_INTR_VEC_BASE 0x25
-#define AUX_IRQ_LEV 0x200 /* IRQ Priority: L1 or L2 */
-#define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */
-#define AUX_IRQ_LV12 0x43 /* interrupt level register */
-
-#define AUX_IENABLE 0x40c
-#define AUX_ITRIGGER 0x40d
-#define AUX_IPULSE 0x415
-
-/* Timer related Aux registers */
-#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */
-#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */
-#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */
-#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */
-#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */
-#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */
-
-#define TIMER_CTRL_IE (1 << 0) /* Interupt when Count reachs limit */
-#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */
-
-/* MMU Management regs */
-#define ARC_REG_TLBPD0 0x405
-#define ARC_REG_TLBPD1 0x406
-#define ARC_REG_TLBINDEX 0x407
-#define ARC_REG_TLBCOMMAND 0x408
-#define ARC_REG_PID 0x409
-#define ARC_REG_SCRATCH_DATA0 0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
-
-/* Error code if probe fails */
-#define TLB_LKUP_ERR 0x80000000
-
-/* TLB Commands */
-#define TLBWrite 0x1
-#define TLBRead 0x2
-#define TLBGetIndex 0x3
-#define TLBProbe 0x4
-
-#if (CONFIG_ARC_MMU_VER >= 2)
-#define TLBWriteNI 0x5 /* write JTLB without inv uTLBs */
-#define TLBIVUTLB 0x6 /* explicitly inv uTLBs */
-#else
-#undef TLBWriteNI /* These cmds don't exist on older MMU */
-#undef TLBIVUTLB
-#endif
-/* Instruction cache related Auxiliary registers */
-#define ARC_REG_IC_BCR 0x77 /* Build Config reg */
-#define ARC_REG_IC_IVIC 0x10
-#define ARC_REG_IC_CTRL 0x11
-#define ARC_REG_IC_IVIL 0x19
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_IC_PTAG 0x1E
-#endif
-
-/* Bit val in IC_CTRL */
-#define IC_CTRL_CACHE_DISABLE 0x1
-
-/* Data cache related Auxiliary registers */
-#define ARC_REG_DC_BCR 0x72
-#define ARC_REG_DC_IVDC 0x47
-#define ARC_REG_DC_CTRL 0x48
-#define ARC_REG_DC_IVDL 0x4A
-#define ARC_REG_DC_FLSH 0x4B
-#define ARC_REG_DC_FLDL 0x4C
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_DC_PTAG 0x5C
-#endif
-
-/* Bit val in DC_CTRL */
-#define DC_CTRL_INV_MODE_FLUSH 0x40
-#define DC_CTRL_FLUSH_STATUS 0x100
-
-/* MMU Management regs */
-#define ARC_REG_PID 0x409
-#define ARC_REG_SCRATCH_DATA0 0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
/*
* Floating Pt Registers
@@ -293,24 +212,6 @@ struct bcr_identity {
#endif
};
-struct bcr_mmu_1_2 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
-#else
- unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
-#endif
-};
-
-struct bcr_mmu_3 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
- u_itlb:4, u_dtlb:4;
-#else
- unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
- ways:4, ver:8;
-#endif
-};
-
#define EXTN_SWAP_VALID 0x1
#define EXTN_NORM_VALID 0x2
#define EXTN_MINMAX_VALID 0x2
@@ -343,14 +244,6 @@ struct bcr_extn_xymem {
#endif
};
-struct bcr_cache {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
-#else
- unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
-#endif
-};
-
struct bcr_perip {
#ifdef CONFIG_CPU_BIG_ENDIAN
unsigned int start:8, pad2:8, sz:8, pad:8;
@@ -403,7 +296,7 @@ struct cpuinfo_arc_mmu {
};
struct cpuinfo_arc_cache {
- unsigned int has_aliasing, sz, line_len, assoc, ver;
+ unsigned int sz, line_len, assoc, ver;
};
struct cpuinfo_arc_ccm {
diff --git a/arch/arc/include/asm/barrier.h b/arch/arc/include/asm/barrier.h
deleted file mode 100644
index f6cb7c4ffb3..00000000000
--- a/arch/arc/include/asm/barrier.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- *
- * 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 __ASM_BARRIER_H
-#define __ASM_BARRIER_H
-
-#ifndef __ASSEMBLY__
-
-/* TODO-vineetg: Need to see what this does, don't we need sync anywhere */
-#define mb() __asm__ __volatile__ ("" : : : "memory")
-#define rmb() mb()
-#define wmb() mb()
-#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-#define read_barrier_depends() mb()
-
-/* TODO-vineetg verify the correctness of macros here */
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
-#else
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#endif
-
-#define smp_mb__before_atomic_dec() barrier()
-#define smp_mb__after_atomic_dec() barrier()
-#define smp_mb__before_atomic_inc() barrier()
-#define smp_mb__after_atomic_inc() barrier()
-
-#define smp_read_barrier_depends() do { } while (0)
-
-#endif
-
-#endif
diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h
index 647a83a8e75..ebc0cf3164d 100644
--- a/arch/arc/include/asm/bitops.h
+++ b/arch/arc/include/asm/bitops.h
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/compiler.h>
+#include <asm/barrier.h>
/*
* Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns.
@@ -496,10 +497,6 @@ static inline __attribute__ ((const)) int __ffs(unsigned long word)
*/
#define ffz(x) __ffs(~(x))
-/* TODO does this affect uni-processor code */
-#define smp_mb__before_clear_bit() barrier()
-#define smp_mb__after_clear_bit() barrier()
-
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/sched.h>
diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h
index 2ad8f9b1c54..5b18e94c667 100644
--- a/arch/arc/include/asm/bug.h
+++ b/arch/arc/include/asm/bug.h
@@ -18,9 +18,8 @@ struct task_struct;
void show_regs(struct pt_regs *regs);
void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs);
void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
- unsigned long address, unsigned long cause_reg);
-void die(const char *str, struct pt_regs *regs, unsigned long address,
- unsigned long cause_reg);
+ unsigned long address);
+void die(const char *str, struct pt_regs *regs, unsigned long address);
#define BUG() do { \
dump_stack(); \
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index 6632273861f..b3c750979aa 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -17,22 +17,14 @@
#endif
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+#define CACHE_LINE_MASK (~(L1_CACHE_BYTES - 1))
-#define ARC_ICACHE_WAYS 2
-#define ARC_DCACHE_WAYS 4
-
-/* Helpers */
-#define ARC_ICACHE_LINE_LEN L1_CACHE_BYTES
-#define ARC_DCACHE_LINE_LEN L1_CACHE_BYTES
-
-#define ICACHE_LINE_MASK (~(ARC_ICACHE_LINE_LEN - 1))
-#define DCACHE_LINE_MASK (~(ARC_DCACHE_LINE_LEN - 1))
-
-#if ARC_ICACHE_LINE_LEN != ARC_DCACHE_LINE_LEN
-#error "Need to fix some code as I/D cache lines not same"
-#else
-#define is_not_cache_aligned(p) ((unsigned long)p & (~DCACHE_LINE_MASK))
-#endif
+/*
+ * ARC700 doesn't cache any access in top 256M.
+ * Ideal for wiring memory mapped peripherals as we don't need to do
+ * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
+ */
+#define ARC_UNCACHED_ADDR_SPACE 0xc0000000
#ifndef __ASSEMBLY__
@@ -55,21 +47,39 @@
: "r"(data), "r"(ptr)); \
})
-/* used to give SHMLBA a value to avoid Cache Aliasing */
-extern unsigned int ARC_shmlba;
-
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
-/*
- * ARC700 doesn't cache any access in top 256M.
- * Ideal for wiring memory mapped peripherals as we don't need to do
- * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
- */
-#define ARC_UNCACHED_ADDR_SPACE 0xc0000000
-
extern void arc_cache_init(void);
extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
-extern void __init read_decode_cache_bcr(void);
+extern void read_decode_cache_bcr(void);
+
+#endif /* !__ASSEMBLY__ */
+
+/* Instruction cache related Auxiliary registers */
+#define ARC_REG_IC_BCR 0x77 /* Build Config reg */
+#define ARC_REG_IC_IVIC 0x10
+#define ARC_REG_IC_CTRL 0x11
+#define ARC_REG_IC_IVIL 0x19
+#if defined(CONFIG_ARC_MMU_V3)
+#define ARC_REG_IC_PTAG 0x1E
+#endif
+
+/* Bit val in IC_CTRL */
+#define IC_CTRL_CACHE_DISABLE 0x1
+
+/* Data cache related Auxiliary registers */
+#define ARC_REG_DC_BCR 0x72 /* Build Config reg */
+#define ARC_REG_DC_IVDC 0x47
+#define ARC_REG_DC_CTRL 0x48
+#define ARC_REG_DC_IVDL 0x4A
+#define ARC_REG_DC_FLSH 0x4B
+#define ARC_REG_DC_FLDL 0x4C
+#if defined(CONFIG_ARC_MMU_V3)
+#define ARC_REG_DC_PTAG 0x5C
#endif
+/* Bit val in DC_CTRL */
+#define DC_CTRL_INV_MODE_FLUSH 0x40
+#define DC_CTRL_FLUSH_STATUS 0x100
+
#endif /* _ASM_CACHE_H */
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
index 97ee96f2650..6abc4972bc9 100644
--- a/arch/arc/include/asm/cacheflush.h
+++ b/arch/arc/include/asm/cacheflush.h
@@ -19,13 +19,24 @@
#define _ASM_CACHEFLUSH_H
#include <linux/mm.h>
+#include <asm/shmparam.h>
+
+/*
+ * Semantically we need this because icache doesn't snoop dcache/dma.
+ * However ARC Cache flush requires paddr as well as vaddr, latter not available
+ * in the flush_icache_page() API. So we no-op it but do the equivalent work
+ * in update_mmu_cache()
+ */
+#define flush_icache_page(vma, page)
void flush_cache_all(void);
void flush_icache_range(unsigned long start, unsigned long end);
-void flush_icache_page(struct vm_area_struct *vma, struct page *page);
-void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
- int len);
+void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len);
+void __inv_icache_page(unsigned long paddr, unsigned long vaddr);
+void ___flush_dcache_page(unsigned long paddr, unsigned long vaddr);
+#define __flush_dcache_page(p, v) \
+ ___flush_dcache_page((unsigned long)p, (unsigned long)v)
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
@@ -42,23 +53,65 @@ void dma_cache_wback(unsigned long start, unsigned long sz);
#define flush_cache_vmap(start, end) flush_cache_all()
#define flush_cache_vunmap(start, end) flush_cache_all()
-/*
- * VM callbacks when entire/range of user-space V-P mappings are
- * torn-down/get-invalidated
- *
- * Currently we don't support D$ aliasing configs for our VIPT caches
- * NOPS for VIPT Cache with non-aliasing D$ configurations only
- */
-#define flush_cache_dup_mm(mm) /* called on fork */
+#define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */
+
+#ifndef CONFIG_ARC_CACHE_VIPT_ALIASING
+
#define flush_cache_mm(mm) /* called on munmap/exit */
#define flush_cache_range(mm, u_vstart, u_vend)
#define flush_cache_page(vma, u_vaddr, pfn) /* PF handling/COW-break */
+#else /* VIPT aliasing dcache */
+
+/* To clear out stale userspace mappings */
+void flush_cache_mm(struct mm_struct *mm);
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start,unsigned long end);
+void flush_cache_page(struct vm_area_struct *vma,
+ unsigned long user_addr, unsigned long page);
+
+/*
+ * To make sure that userspace mapping is flushed to memory before
+ * get_user_pages() uses a kernel mapping to access the page
+ */
+#define ARCH_HAS_FLUSH_ANON_PAGE
+void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long u_vaddr);
+
+#endif /* CONFIG_ARC_CACHE_VIPT_ALIASING */
+
+/*
+ * A new pagecache page has PG_arch_1 clear - thus dcache dirty by default
+ * This works around some PIO based drivers which don't call flush_dcache_page
+ * to record that they dirtied the dcache
+ */
+#define PG_dc_clean PG_arch_1
+
+/*
+ * Simple wrapper over config option
+ * Bootup code ensures that hardware matches kernel configuration
+ */
+static inline int cache_is_vipt_aliasing(void)
+{
+ return IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
+}
+
+#define CACHE_COLOR(addr) (((unsigned long)(addr) >> (PAGE_SHIFT)) & 1)
+
+/*
+ * checks if two addresses (after page aligning) index into same cache set
+ */
+#define addr_not_cache_congruent(addr1, addr2) \
+({ \
+ cache_is_vipt_aliasing() ? \
+ (CACHE_COLOR(addr1) != CACHE_COLOR(addr2)) : 0; \
+})
+
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
do { \
memcpy(dst, src, len); \
if (vma->vm_flags & VM_EXEC) \
- flush_icache_range_vaddr((unsigned long)(dst), vaddr, len);\
+ __sync_icache_dcache((unsigned long)(dst), vaddr, len); \
} while (0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
diff --git a/arch/arc/include/asm/defines.h b/arch/arc/include/asm/defines.h
deleted file mode 100644
index 6097bb439cc..00000000000
--- a/arch/arc/include/asm/defines.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- *
- * 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 __ARC_ASM_DEFINES_H__
-#define __ARC_ASM_DEFINES_H__
-
-#if defined(CONFIG_ARC_MMU_V1)
-#define CONFIG_ARC_MMU_VER 1
-#elif defined(CONFIG_ARC_MMU_V2)
-#define CONFIG_ARC_MMU_VER 2
-#elif defined(CONFIG_ARC_MMU_V3)
-#define CONFIG_ARC_MMU_VER 3
-#endif
-
-#ifdef CONFIG_ARC_HAS_LLSC
-#define __CONFIG_ARC_HAS_LLSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_LLSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_SWAPE
-#define __CONFIG_ARC_HAS_SWAPE_VAL 1
-#else
-#define __CONFIG_ARC_HAS_SWAPE_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_RTSC
-#define __CONFIG_ARC_HAS_RTSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_RTSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_MMU_SASID
-#define __CONFIG_ARC_MMU_SASID_VAL 1
-#else
-#define __CONFIG_ARC_MMU_SASID_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_ICACHE
-#define __CONFIG_ARC_HAS_ICACHE 1
-#else
-#define __CONFIG_ARC_HAS_ICACHE 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_DCACHE
-#define __CONFIG_ARC_HAS_DCACHE 1
-#else
-#define __CONFIG_ARC_HAS_DCACHE 0
-#endif
-
-#endif /* __ARC_ASM_DEFINES_H__ */
diff --git a/arch/arc/include/asm/delay.h b/arch/arc/include/asm/delay.h
index 442ce5d0f70..43de3025698 100644
--- a/arch/arc/include/asm/delay.h
+++ b/arch/arc/include/asm/delay.h
@@ -53,11 +53,10 @@ static inline void __udelay(unsigned long usecs)
{
unsigned long loops;
- /* (long long) cast ensures 64 bit MPY - real or emulated
+ /* (u64) cast ensures 64 bit MPY - real or emulated
* HZ * 4295 is pre-evaluated by gcc - hence only 2 mpy ops
*/
- loops = ((long long)(usecs * 4295 * HZ) *
- (long long)(loops_per_jiffy)) >> 32;
+ loops = ((u64) usecs * 4295 * HZ * loops_per_jiffy) >> 32;
__delay(loops);
}
diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h
index 31f77aec082..45b8e0cea17 100644
--- a/arch/arc/include/asm/dma-mapping.h
+++ b/arch/arc/include/asm/dma-mapping.h
@@ -126,7 +126,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg,
int i;
for_each_sg(sg, s, nents, i)
- sg->dma_address = dma_map_page(dev, sg_page(s), s->offset,
+ s->dma_address = dma_map_page(dev, sg_page(s), s->offset,
s->length, dir);
return nents;
diff --git a/arch/arc/include/asm/elf.h b/arch/arc/include/asm/elf.h
index f4c8d36ebec..a2628285768 100644
--- a/arch/arc/include/asm/elf.h
+++ b/arch/arc/include/asm/elf.h
@@ -72,7 +72,4 @@ extern int elf_check_arch(const struct elf32_hdr *);
*/
#define ELF_PLATFORM (NULL)
-#define SET_PERSONALITY(ex) \
- set_personality(PER_LINUX | (current->personality & (~PER_MASK)))
-
#endif
diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h
index 23daa326fc9..884081099f8 100644
--- a/arch/arc/include/asm/entry.h
+++ b/arch/arc/include/asm/entry.h
@@ -38,6 +38,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h> /* For VMALLOC_START */
#include <asm/thread_info.h> /* For THREAD_SIZE */
+#include <asm/mmu.h>
/* Note on the LD/ST addr modes with addr reg wback
*
@@ -50,194 +51,177 @@
* Eff Addr for load = [reg2]
*/
+.macro PUSH reg
+ st.a \reg, [sp, -4]
+.endm
+
+.macro PUSHAX aux
+ lr r9, [\aux]
+ PUSH r9
+.endm
+
+.macro POP reg
+ ld.ab \reg, [sp, 4]
+.endm
+
+.macro POPAX aux
+ POP r9
+ sr r9, [\aux]
+.endm
+
/*--------------------------------------------------------------
- * Save caller saved registers (scratch registers) ( r0 - r12 )
- * Registers are pushed / popped in the order defined in struct ptregs
- * in asm/ptrace.h
+ * Helpers to save/restore Scratch Regs:
+ * used by Interrupt/Exception Prologue/Epilogue
*-------------------------------------------------------------*/
-.macro SAVE_CALLER_SAVED
- st.a r0, [sp, -4]
- st.a r1, [sp, -4]
- st.a r2, [sp, -4]
- st.a r3, [sp, -4]
- st.a r4, [sp, -4]
- st.a r5, [sp, -4]
- st.a r6, [sp, -4]
- st.a r7, [sp, -4]
- st.a r8, [sp, -4]
- st.a r9, [sp, -4]
- st.a r10, [sp, -4]
- st.a r11, [sp, -4]
- st.a r12, [sp, -4]
+.macro SAVE_R0_TO_R12
+ PUSH r0
+ PUSH r1
+ PUSH r2
+ PUSH r3
+ PUSH r4
+ PUSH r5
+ PUSH r6
+ PUSH r7
+ PUSH r8
+ PUSH r9
+ PUSH r10
+ PUSH r11
+ PUSH r12
+.endm
+
+.macro RESTORE_R12_TO_R0
+ POP r12
+ POP r11
+ POP r10
+ POP r9
+ POP r8
+ POP r7
+ POP r6
+ POP r5
+ POP r4
+ POP r3
+ POP r2
+ POP r1
+ POP r0
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+ ld r25, [sp, 12]
+#endif
.endm
/*--------------------------------------------------------------
- * Restore caller saved registers (scratch registers)
+ * Helpers to save/restore callee-saved regs:
+ * used by several macros below
*-------------------------------------------------------------*/
-.macro RESTORE_CALLER_SAVED
- ld.ab r12, [sp, 4]
- ld.ab r11, [sp, 4]
- ld.ab r10, [sp, 4]
- ld.ab r9, [sp, 4]
- ld.ab r8, [sp, 4]
- ld.ab r7, [sp, 4]
- ld.ab r6, [sp, 4]
- ld.ab r5, [sp, 4]
- ld.ab r4, [sp, 4]
- ld.ab r3, [sp, 4]
- ld.ab r2, [sp, 4]
- ld.ab r1, [sp, 4]
- ld.ab r0, [sp, 4]
+.macro SAVE_R13_TO_R24
+ PUSH r13
+ PUSH r14
+ PUSH r15
+ PUSH r16
+ PUSH r17
+ PUSH r18
+ PUSH r19
+ PUSH r20
+ PUSH r21
+ PUSH r22
+ PUSH r23
+ PUSH r24
+.endm
+
+.macro RESTORE_R24_TO_R13
+ POP r24
+ POP r23
+ POP r22
+ POP r21
+ POP r20
+ POP r19
+ POP r18
+ POP r17
+ POP r16
+ POP r15
+ POP r14
+ POP r13
.endm
+#define OFF_USER_R25_FROM_R24 (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
/*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- * on kernel stack.
- * User mode callee regs need to be saved in case of
- * -fork and friends for replicating from parent to child
- * -before going into do_signal( ) for ptrace/core-dump
- * Special case handling is required for r25 in case it is used by kernel
- * for caching task ptr. Low level exception/ISR save user mode r25
- * into task->thread.user_r25. So it needs to be retrieved from there and
- * saved into kernel stack with rest of callee reg-file
+ * Collect User Mode callee regs as struct callee_regs - needed by
+ * fork/do_signal/unaligned-access-emulation.
+ * (By default only scratch regs are saved on entry to kernel)
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * It would have been saved in task->thread.user_r25 already, but to keep
+ * the interface same it is copied into regular r25 placeholder in
+ * struct callee_regs.
*-------------------------------------------------------------*/
.macro SAVE_CALLEE_SAVED_USER
- st.a r13, [sp, -4]
- st.a r14, [sp, -4]
- st.a r15, [sp, -4]
- st.a r16, [sp, -4]
- st.a r17, [sp, -4]
- st.a r18, [sp, -4]
- st.a r19, [sp, -4]
- st.a r20, [sp, -4]
- st.a r21, [sp, -4]
- st.a r22, [sp, -4]
- st.a r23, [sp, -4]
- st.a r24, [sp, -4]
+
+ SAVE_R13_TO_R24
#ifdef CONFIG_ARC_CURR_IN_REG
; Retrieve orig r25 and save it on stack
- ld r12, [r25, TASK_THREAD + THREAD_USER_R25]
+ ld.as r12, [sp, OFF_USER_R25_FROM_R24]
st.a r12, [sp, -4]
#else
- st.a r25, [sp, -4]
+ PUSH r25
#endif
- /* move up by 1 word to "create" callee_regs->"stack_place_holder" */
- sub sp, sp, 4
.endm
/*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- * kernel mode callee regs needed to be saved in case of context switch
- * If r25 is used for caching task pointer then that need not be saved
- * as it can be re-created from current task global
+ * Save kernel Mode callee regs at the time of Contect Switch.
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * Kernel simply skips saving it since it will be loaded with
+ * incoming task pointer anyways
*-------------------------------------------------------------*/
.macro SAVE_CALLEE_SAVED_KERNEL
- st.a r13, [sp, -4]
- st.a r14, [sp, -4]
- st.a r15, [sp, -4]
- st.a r16, [sp, -4]
- st.a r17, [sp, -4]
- st.a r18, [sp, -4]
- st.a r19, [sp, -4]
- st.a r20, [sp, -4]
- st.a r21, [sp, -4]
- st.a r22, [sp, -4]
- st.a r23, [sp, -4]
- st.a r24, [sp, -4]
+
+ SAVE_R13_TO_R24
+
#ifdef CONFIG_ARC_CURR_IN_REG
- sub sp, sp, 8
-#else
- st.a r25, [sp, -4]
sub sp, sp, 4
+#else
+ PUSH r25
#endif
.endm
/*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_KERNEL:
- * Loads callee (non scratch) Reg File by popping from Kernel mode stack.
- * This is reverse of SAVE_CALLEE_SAVED,
- *
- * NOTE:
- * Ideally this shd only be called in switch_to for loading
- * switched-IN task's CALLEE Reg File.
- * For all other cases RESTORE_CALLEE_SAVED_FAST must be used
- * which simply pops the stack w/o touching regs.
+ * Opposite of SAVE_CALLEE_SAVED_KERNEL
*-------------------------------------------------------------*/
.macro RESTORE_CALLEE_SAVED_KERNEL
-
#ifdef CONFIG_ARC_CURR_IN_REG
- add sp, sp, 8 /* skip callee_reg gutter and user r25 placeholder */
+ add sp, sp, 4 /* skip usual r25 placeholder */
#else
- add sp, sp, 4 /* skip "callee_regs->stack_place_holder" */
- ld.ab r25, [sp, 4]
+ POP r25
#endif
-
- ld.ab r24, [sp, 4]
- ld.ab r23, [sp, 4]
- ld.ab r22, [sp, 4]
- ld.ab r21, [sp, 4]
- ld.ab r20, [sp, 4]
- ld.ab r19, [sp, 4]
- ld.ab r18, [sp, 4]
- ld.ab r17, [sp, 4]
- ld.ab r16, [sp, 4]
- ld.ab r15, [sp, 4]
- ld.ab r14, [sp, 4]
- ld.ab r13, [sp, 4]
-
+ RESTORE_R24_TO_R13
.endm
/*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_USER:
- * This is called after do_signal where tracer might have changed callee regs
- * thus we need to restore the reg file.
- * Special case handling is required for r25 in case it is used by kernel
- * for caching task ptr. Ptrace would have modified on-kernel-stack value of
- * r25, which needs to be shoved back into task->thread.user_r25 where from
- * Low level exception/ISR return code will retrieve to populate with rest of
- * callee reg-file.
+ * Opposite of SAVE_CALLEE_SAVED_USER
+ *
+ * ptrace tracer or unaligned-access fixup might have changed a user mode
+ * callee reg which is saved back to usual r25 storage location
*-------------------------------------------------------------*/
.macro RESTORE_CALLEE_SAVED_USER
- add sp, sp, 4 /* skip "callee_regs->stack_place_holder" */
-
#ifdef CONFIG_ARC_CURR_IN_REG
ld.ab r12, [sp, 4]
- st r12, [r25, TASK_THREAD + THREAD_USER_R25]
+ st.as r12, [sp, OFF_USER_R25_FROM_R24]
#else
- ld.ab r25, [sp, 4]
+ POP r25
#endif
-
- ld.ab r24, [sp, 4]
- ld.ab r23, [sp, 4]
- ld.ab r22, [sp, 4]
- ld.ab r21, [sp, 4]
- ld.ab r20, [sp, 4]
- ld.ab r19, [sp, 4]
- ld.ab r18, [sp, 4]
- ld.ab r17, [sp, 4]
- ld.ab r16, [sp, 4]
- ld.ab r15, [sp, 4]
- ld.ab r14, [sp, 4]
- ld.ab r13, [sp, 4]
+ RESTORE_R24_TO_R13
.endm
/*--------------------------------------------------------------
* Super FAST Restore callee saved regs by simply re-adjusting SP
*-------------------------------------------------------------*/
.macro DISCARD_CALLEE_SAVED_USER
- add sp, sp, 14 * 4
-.endm
-
-/*--------------------------------------------------------------
- * Restore User mode r25 saved in task_struct->thread.user_r25
- *-------------------------------------------------------------*/
-.macro RESTORE_USER_R25
- ld r25, [r25, TASK_THREAD + THREAD_USER_R25]
+ add sp, sp, SZ_CALLEE_REGS
.endm
/*-------------------------------------------------------------
@@ -252,7 +236,7 @@
ld \out, [\tsk, TASK_THREAD_INFO]
/* Go to end of page where stack begins (grows upwards) */
- add2 \out, \out, (THREAD_SIZE - 4)/4 /* one word GUTTER */
+ add2 \out, \out, (THREAD_SIZE)/4
.endm
@@ -305,33 +289,28 @@
* safe-keeping not really needed, but it keeps the epilogue code
* (SP restore) simpler/uniform.
*/
- b.d 77f
-
- st.a sp, [sp, -12] ; Make room for orig_r0 and orig_r8
+ b.d 66f
+ mov r9, sp
88: /*------Intr/Ecxp happened in user mode, "switch" stack ------ */
GET_CURR_TASK_ON_CPU r9
-#ifdef CONFIG_ARC_CURR_IN_REG
-
- /* If current task pointer cached in r25, time to
- * -safekeep USER r25 in task->thread_struct->user_r25
- * -load r25 with current task ptr
- */
- st.as r25, [r9, (TASK_THREAD + THREAD_USER_R25)/4]
- mov r25, r9
-#endif
-
/* With current tsk in r9, get it's kernel mode stack base */
GET_TSK_STACK_BASE r9, r9
-#ifdef PT_REGS_CANARY
- st 0xabcdabcd, [r9, 0]
+66:
+#ifdef CONFIG_ARC_CURR_IN_REG
+ /*
+ * Treat r25 as scratch reg, save it on stack first
+ * Load it with current task pointer
+ */
+ st r25, [r9, -4]
+ GET_CURR_TASK_ON_CPU r25
#endif
/* Save Pre Intr/Exception User SP on kernel stack */
- st.a sp, [r9, -12] ; Make room for orig_r0 and orig_r8
+ st.a sp, [r9, -16] ; Make room for orig_r0, ECR, user_r25
/* CAUTION:
* SP should be set at the very end when we are done with everything
@@ -342,7 +321,7 @@
/* set SP to point to kernel mode stack */
mov sp, r9
-77: /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
+ /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
.endm
@@ -369,7 +348,7 @@
* @reg [OUT] &thread_info of "current"
*/
.macro GET_CURR_THR_INFO_FROM_SP reg
- and \reg, sp, ~(THREAD_SIZE - 1)
+ bic \reg, sp, (THREAD_SIZE - 1)
.endm
/*
@@ -386,7 +365,7 @@
* it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP).
*
* Before saving the full regfile - this reg is restored back, only
- * to be saved again on kernel mode stack, as part of ptregs.
+ * to be saved again on kernel mode stack, as part of pt_regs.
*-------------------------------------------------------------*/
.macro EXCPN_PROLOG_FREEUP_REG reg
#ifdef CONFIG_SMP
@@ -405,6 +384,28 @@
.endm
/*--------------------------------------------------------------
+ * Exception Entry prologue
+ * -Switches stack to K mode (if not already)
+ * -Saves the register file
+ *
+ * After this it is safe to call the "C" handlers
+ *-------------------------------------------------------------*/
+.macro EXCEPTION_PROLOGUE
+
+ /* Need at least 1 reg to code the early exception prologue */
+ EXCPN_PROLOG_FREEUP_REG r9
+
+ /* U/K mode at time of exception (stack not switched if already K) */
+ lr r9, [erstatus]
+
+ /* ARC700 doesn't provide auto-stack switching */
+ SWITCH_TO_KERNEL_STK
+
+ /* save the regfile */
+ SAVE_ALL_SYS
+.endm
+
+/*--------------------------------------------------------------
* Save all registers used by Exceptions (TLB Miss, Prot-V, Mem err etc)
* Requires SP to be already switched to kernel mode Stack
* sp points to the next free element on the stack at exit of this macro.
@@ -413,62 +414,25 @@
* Note that syscalls are implemented via TRAP which is also a exception
* from CPU's point of view
*-------------------------------------------------------------*/
-.macro SAVE_ALL_EXCEPTION marker
+.macro SAVE_ALL_SYS
- st \marker, [sp, 8]
+ lr r9, [ecr]
+ st r9, [sp, 8] /* ECR */
st r0, [sp, 4] /* orig_r0, needed only for sys calls */
/* Restore r9 used to code the early prologue */
EXCPN_PROLOG_RESTORE_REG r9
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- lr r9, [eret]
- st.a r9, [sp, -4]
- lr r9, [erstatus]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [erbta]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbeef
- st r9, [sp, -4]
-#endif
-
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for exceptions
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_SYS
- SAVE_ALL_EXCEPTION orig_r8_IS_EXCPN
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for sys calls
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_TRAP
- /*
- * Setup pt_regs->orig_r8.
- * Encode syscall number (r8) in upper short word of event type (r9)
- * N.B. #1: This is already endian safe (see ptrace.h)
- * #2: Only r9 can be used as scratch as it is already clobbered
- * and it's contents are no longer needed by the latter part
- * of exception prologue
- */
- lsl r9, r8, 16
- or r9, r9, orig_r8_IS_SCALL
-
- SAVE_ALL_EXCEPTION r9
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSHAX eret
+ PUSHAX erstatus
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX erbta
.endm
/*--------------------------------------------------------------
@@ -483,28 +447,22 @@
* by hardware and that is not good.
*-------------------------------------------------------------*/
.macro RESTORE_ALL_SYS
+ POPAX erbta
+ POPAX lp_start
+ POPAX lp_end
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4]
- sr r9, [erbta]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [erstatus]
- ld.ab r9, [sp, 4]
- sr r9, [eret]
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
+
+ POPAX erstatus
+ POPAX eret
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
@@ -513,9 +471,7 @@
*-------------------------------------------------------------*/
.macro SAVE_ALL_INT1
- /* restore original r9 , saved in int1_saved_reg
- * It will be saved on stack in macro: SAVE_CALLER_SAVED
- */
+ /* restore original r9 to be saved as part of reg-file */
#ifdef CONFIG_SMP
lr r9, [ARC_REG_SCRATCH_DATA0]
#else
@@ -523,29 +479,19 @@
#endif
/* now we are ready to save the remaining context :) */
- st orig_r8_IS_IRQ1, [sp, 8] /* Event Type */
+ st event_IRQ1, [sp, 8] /* Dummy ECR */
st 0, [sp, 4] /* orig_r0 , N/A for IRQ */
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- st.a ilink1, [sp, -4]
- lr r9, [status32_l1]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [bta_l1]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbee1
- st r9, [sp, -4]
-#endif
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
+
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSH ilink1
+ PUSHAX status32_l1
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX bta_l1
.endm
.macro SAVE_ALL_INT2
@@ -558,30 +504,19 @@
ld r9, [@int2_saved_reg]
/* now we are ready to save the remaining context :) */
- st orig_r8_IS_IRQ2, [sp, 8] /* Event Type */
+ st event_IRQ2, [sp, 8] /* Dummy ECR */
st 0, [sp, 4] /* orig_r0 , N/A for IRQ */
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- st.a ilink2, [sp, -4]
- lr r9, [status32_l2]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [bta_l2]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbee2
- st r9, [sp, -4]
-#endif
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSH ilink2
+ PUSHAX status32_l2
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX bta_l2
.endm
/*--------------------------------------------------------------
@@ -595,52 +530,41 @@
*-------------------------------------------------------------*/
.macro RESTORE_ALL_INT1
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4] /* Actual reg file */
- sr r9, [bta_l1]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [status32_l1]
- ld.ab r9, [sp, 4]
- mov ilink1, r9
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POPAX bta_l1
+ POPAX lp_start
+ POPAX lp_end
+
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
+
+ POPAX status32_l1
+ POP ilink1
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
.macro RESTORE_ALL_INT2
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4]
- sr r9, [bta_l2]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [status32_l2]
- ld.ab r9, [sp, 4]
- mov ilink2, r9
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POPAX bta_l2
+ POPAX lp_start
+ POPAX lp_end
- ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
+ POPAX status32_l2
+ POP ilink2
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
+
+ ld sp, [sp] /* restore original sp */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index 473424d7528..334ce7017a1 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -100,6 +100,10 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
}
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
+
#include <asm-generic/io.h>
#endif /* _ASM_ARC_IO_H */
diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h
index 4c588f9820c..fb4efb64897 100644
--- a/arch/arc/include/asm/irq.h
+++ b/arch/arc/include/asm/irq.h
@@ -9,7 +9,8 @@
#ifndef __ASM_ARC_IRQ_H
#define __ASM_ARC_IRQ_H
-#define NR_IRQS 32
+#define NR_CPU_IRQS 32 /* number of interrupt lines of ARC770 CPU */
+#define NR_IRQS 128 /* allow some CPU external IRQ handling */
/* Platform Independent IRQs */
#define TIMER0_IRQ 3
@@ -17,9 +18,7 @@
#include <asm-generic/irq.h>
-extern void __init arc_init_IRQ(void);
-extern int __init get_hw_config_num_irq(void);
-
-void __cpuinit arc_local_timer_setup(unsigned int cpu);
+extern void arc_init_IRQ(void);
+void arc_local_timer_setup(void);
#endif
diff --git a/arch/arc/include/asm/irqflags.h b/arch/arc/include/asm/irqflags.h
index ccd84806b62..cb7efc29f16 100644
--- a/arch/arc/include/asm/irqflags.h
+++ b/arch/arc/include/asm/irqflags.h
@@ -19,6 +19,26 @@
#include <asm/arcregs.h>
+/* status32 Reg bits related to Interrupt Handling */
+#define STATUS_E1_BIT 1 /* Int 1 enable */
+#define STATUS_E2_BIT 2 /* Int 2 enable */
+#define STATUS_A1_BIT 3 /* Int 1 active */
+#define STATUS_A2_BIT 4 /* Int 2 active */
+
+#define STATUS_E1_MASK (1<<STATUS_E1_BIT)
+#define STATUS_E2_MASK (1<<STATUS_E2_BIT)
+#define STATUS_A1_MASK (1<<STATUS_A1_BIT)
+#define STATUS_A2_MASK (1<<STATUS_A2_BIT)
+
+/* Other Interrupt Handling related Aux regs */
+#define AUX_IRQ_LEV 0x200 /* IRQ Priority: L1 or L2 */
+#define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */
+#define AUX_IRQ_LV12 0x43 /* interrupt level register */
+
+#define AUX_IENABLE 0x40c
+#define AUX_ITRIGGER 0x40d
+#define AUX_IPULSE 0x415
+
#ifndef __ASSEMBLY__
/******************************************************************
@@ -39,7 +59,7 @@ static inline long arch_local_irq_save(void)
" flag.nz %0 \n"
: "=r"(temp), "=r"(flags)
: "n"((STATUS_E1_MASK | STATUS_E2_MASK))
- : "cc");
+ : "memory", "cc");
return flags;
}
@@ -53,7 +73,8 @@ static inline void arch_local_irq_restore(unsigned long flags)
__asm__ __volatile__(
" flag %0 \n"
:
- : "r"(flags));
+ : "r"(flags)
+ : "memory");
}
/*
@@ -73,7 +94,8 @@ static inline void arch_local_irq_disable(void)
" and %0, %0, %1 \n"
" flag %0 \n"
: "=&r"(temp)
- : "n"(~(STATUS_E1_MASK | STATUS_E2_MASK)));
+ : "n"(~(STATUS_E1_MASK | STATUS_E2_MASK))
+ : "memory");
}
/*
@@ -85,7 +107,9 @@ static inline long arch_local_save_flags(void)
__asm__ __volatile__(
" lr %0, [status32] \n"
- : "=&r"(temp));
+ : "=&r"(temp)
+ :
+ : "memory");
return temp;
}
@@ -127,23 +151,38 @@ static inline void arch_unmask_irq(unsigned int irq)
#else
-.macro IRQ_DISABLE scratch
- lr \scratch, [status32]
- bic \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
- flag \scratch
+#ifdef CONFIG_TRACE_IRQFLAGS
+
+.macro TRACE_ASM_IRQ_DISABLE
+ bl trace_hardirqs_off
+.endm
+
+.macro TRACE_ASM_IRQ_ENABLE
+ bl trace_hardirqs_on
.endm
-.macro IRQ_DISABLE_SAVE scratch, save
+#else
+
+.macro TRACE_ASM_IRQ_DISABLE
+.endm
+
+.macro TRACE_ASM_IRQ_ENABLE
+.endm
+
+#endif
+
+.macro IRQ_DISABLE scratch
lr \scratch, [status32]
- mov \save, \scratch /* Make a copy */
bic \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
flag \scratch
+ TRACE_ASM_IRQ_DISABLE
.endm
.macro IRQ_ENABLE scratch
lr \scratch, [status32]
or \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
flag \scratch
+ TRACE_ASM_IRQ_ENABLE
.endm
#endif /* __ASSEMBLY__ */
diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h
index f3c4934f0ca..b65fca7ffeb 100644
--- a/arch/arc/include/asm/kgdb.h
+++ b/arch/arc/include/asm/kgdb.h
@@ -13,7 +13,7 @@
#ifdef CONFIG_KGDB
-#include <asm/user.h>
+#include <asm/ptrace.h>
/* to ensure compatibility with Linux 2.6.35, we don't implement the get/set
* register API yet */
@@ -31,7 +31,7 @@ static inline void arch_kgdb_breakpoint(void)
__asm__ __volatile__ ("trap_s 0x4\n");
}
-extern void kgdb_trap(struct pt_regs *regs, int param);
+extern void kgdb_trap(struct pt_regs *regs);
enum arc700_linux_regnums {
_R0 = 0,
@@ -53,9 +53,7 @@ enum arc700_linux_regnums {
};
#else
-static inline void kgdb_trap(struct pt_regs *regs, int param)
-{
-}
+#define kgdb_trap(regs)
#endif
#endif /* __ARC_KGDB_H__ */
diff --git a/arch/arc/include/asm/kprobes.h b/arch/arc/include/asm/kprobes.h
index 4d9c211fce7..944dbedb38b 100644
--- a/arch/arc/include/asm/kprobes.h
+++ b/arch/arc/include/asm/kprobes.h
@@ -50,11 +50,9 @@ struct kprobe_ctlblk {
int kprobe_fault_handler(struct pt_regs *regs, unsigned long cause);
void kretprobe_trampoline(void);
-void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs);
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs);
#else
-static void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+static void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
{
}
#endif
diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h
index 0283e9e44e0..5faad17118b 100644
--- a/arch/arc/include/asm/linkage.h
+++ b/arch/arc/include/asm/linkage.h
@@ -11,19 +11,7 @@
#ifdef __ASSEMBLY__
-/* Can't use the ENTRY macro in linux/linkage.h
- * gas considers ';' as comment vs. newline
- */
-.macro ARC_ENTRY name
- .global \name
- .align 4
- \name:
-.endm
-
-.macro ARC_EXIT name
-#define ASM_PREV_SYM_ADDR(name) .-##name
- .size \ name, ASM_PREV_SYM_ADDR(\name)
-.endm
+#define ASM_NL ` /* use '`' to mark new line in macro */
/* annotation for data we want in DCCM - if enabled in .config */
.macro ARCFP_DATA nm
diff --git a/arch/arc/include/asm/mach_desc.h b/arch/arc/include/asm/mach_desc.h
index 9998dc846eb..e8993a2be6c 100644
--- a/arch/arc/include/asm/mach_desc.h
+++ b/arch/arc/include/asm/mach_desc.h
@@ -51,22 +51,12 @@ struct machine_desc {
/*
* Current machine - only accessible during boot.
*/
-extern struct machine_desc *machine_desc;
+extern const struct machine_desc *machine_desc;
/*
* Machine type table - also only accessible during boot
*/
-extern struct machine_desc __arch_info_begin[], __arch_info_end[];
-#define for_each_machine_desc(p) \
- for (p = __arch_info_begin; p < __arch_info_end; p++)
-
-static inline struct machine_desc *default_machine_desc(void)
-{
- /* the default machine is the last one linked in */
- if (__arch_info_end - 1 < __arch_info_begin)
- return NULL;
- return __arch_info_end - 1;
-}
+extern const struct machine_desc __arch_info_begin[], __arch_info_end[];
/*
* Set of macros to define architecture features.
@@ -81,7 +71,6 @@ __attribute__((__section__(".arch.info.init"))) = { \
#define MACHINE_END \
};
-extern struct machine_desc *setup_machine_fdt(void *dt);
-extern void __init copy_devtree(void);
+extern const struct machine_desc *setup_machine_fdt(void *dt);
#endif
diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h
index 56b02320f1a..8c84ae98c33 100644
--- a/arch/arc/include/asm/mmu.h
+++ b/arch/arc/include/asm/mmu.h
@@ -9,15 +9,58 @@
#ifndef _ASM_ARC_MMU_H
#define _ASM_ARC_MMU_H
+#if defined(CONFIG_ARC_MMU_V1)
+#define CONFIG_ARC_MMU_VER 1
+#elif defined(CONFIG_ARC_MMU_V2)
+#define CONFIG_ARC_MMU_VER 2
+#elif defined(CONFIG_ARC_MMU_V3)
+#define CONFIG_ARC_MMU_VER 3
+#endif
+
+/* MMU Management regs */
+#define ARC_REG_MMU_BCR 0x06f
+#define ARC_REG_TLBPD0 0x405
+#define ARC_REG_TLBPD1 0x406
+#define ARC_REG_TLBINDEX 0x407
+#define ARC_REG_TLBCOMMAND 0x408
+#define ARC_REG_PID 0x409
+#define ARC_REG_SCRATCH_DATA0 0x418
+
+/* Bits in MMU PID register */
+#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
+
+/* Error code if probe fails */
+#define TLB_LKUP_ERR 0x80000000
+
+#define TLB_DUP_ERR (TLB_LKUP_ERR | 0x00000001)
+
+/* TLB Commands */
+#define TLBWrite 0x1
+#define TLBRead 0x2
+#define TLBGetIndex 0x3
+#define TLBProbe 0x4
+
+#if (CONFIG_ARC_MMU_VER >= 2)
+#define TLBWriteNI 0x5 /* write JTLB without inv uTLBs */
+#define TLBIVUTLB 0x6 /* explicitly inv uTLBs */
+#endif
+
#ifndef __ASSEMBLY__
typedef struct {
- unsigned long asid; /* Pvt Addr-Space ID for mm */
-#ifdef CONFIG_ARC_TLB_DBG
- struct task_struct *tsk;
-#endif
+ unsigned long asid[NR_CPUS]; /* 8 bit MMU PID + Generation cycle */
} mm_context_t;
+#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
+void tlb_paranoid_check(unsigned int mm_asid, unsigned long address);
+#else
+#define tlb_paranoid_check(a, b)
#endif
+void arc_mmu_init(void);
+extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
+void read_decode_mmu_bcr(void);
+
+#endif /* !__ASSEMBLY__ */
+
#endif
diff --git a/arch/arc/include/asm/mmu_context.h b/arch/arc/include/asm/mmu_context.h
index 0d71fb11b57..1fd467ef658 100644
--- a/arch/arc/include/asm/mmu_context.h
+++ b/arch/arc/include/asm/mmu_context.h
@@ -30,99 +30,72 @@
* "Fast Context Switch" i.e. no TLB flush on ctxt-switch
*
* Linux assigns each task a unique ASID. A simple round-robin allocation
- * of H/w ASID is done using software tracker @asid_cache.
+ * of H/w ASID is done using software tracker @asid_cpu.
* When it reaches max 255, the allocation cycle starts afresh by flushing
* the entire TLB and wrapping ASID back to zero.
*
- * For book-keeping, Linux uses a couple of data-structures:
- * -mm_struct has an @asid field to keep a note of task's ASID (needed at the
- * time of say switch_mm( )
- * -An array of mm structs @asid_mm_map[] for asid->mm the reverse mapping,
- * given an ASID, finding the mm struct associated.
- *
- * The round-robin allocation algorithm allows for ASID stealing.
- * If asid tracker is at "x-1", a new req will allocate "x", even if "x" was
- * already assigned to another (switched-out) task. Obviously the prev owner
- * is marked with an invalid ASID to make it request for a new ASID when it
- * gets scheduled next time. However its TLB entries (with ASID "x") could
- * exist, which must be cleared before the same ASID is used by the new owner.
- * Flushing them would be plausible but costly solution. Instead we force a
- * allocation policy quirk, which ensures that a stolen ASID won't have any
- * TLB entries associates, alleviating the need to flush.
- * The quirk essentially is not allowing ASID allocated in prev cycle
- * to be used past a roll-over in the next cycle.
- * When this happens (i.e. task ASID > asid tracker), task needs to refresh
- * its ASID, aligning it to current value of tracker. If the task doesn't get
- * scheduled past a roll-over, hence its ASID is not yet realigned with
- * tracker, such ASID is anyways safely reusable because it is
- * gauranteed that TLB entries with that ASID wont exist.
+ * A new allocation cycle, post rollover, could potentially reassign an ASID
+ * to a different task. Thus the rule is to refresh the ASID in a new cycle.
+ * The 32 bit @asid_cpu (and mm->asid) have 8 bits MMU PID and rest 24 bits
+ * serve as cycle/generation indicator and natural 32 bit unsigned math
+ * automagically increments the generation when lower 8 bits rollover.
*/
-#define FIRST_ASID 0
-#define MAX_ASID 255 /* 8 bit PID field in PID Aux reg */
-#define NO_ASID (MAX_ASID + 1) /* ASID Not alloc to mmu ctxt */
-#define NUM_ASID ((MAX_ASID - FIRST_ASID) + 1)
+#define MM_CTXT_ASID_MASK 0x000000ff /* MMU PID reg :8 bit PID */
+#define MM_CTXT_CYCLE_MASK (~MM_CTXT_ASID_MASK)
+
+#define MM_CTXT_FIRST_CYCLE (MM_CTXT_ASID_MASK + 1)
+#define MM_CTXT_NO_ASID 0UL
-/* ASID to mm struct mapping */
-extern struct mm_struct *asid_mm_map[NUM_ASID + 1];
+#define asid_mm(mm, cpu) mm->context.asid[cpu]
+#define hw_pid(mm, cpu) (asid_mm(mm, cpu) & MM_CTXT_ASID_MASK)
-extern int asid_cache;
+DECLARE_PER_CPU(unsigned int, asid_cache);
+#define asid_cpu(cpu) per_cpu(asid_cache, cpu)
/*
- * Assign a new ASID to task. If the task already has an ASID, it is
- * relinquished.
+ * Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle)
+ * Also set the MMU PID register to existing/updated ASID
*/
static inline void get_new_mmu_context(struct mm_struct *mm)
{
- struct mm_struct *prev_owner;
+ const unsigned int cpu = smp_processor_id();
unsigned long flags;
local_irq_save(flags);
/*
- * Relinquish the currently owned ASID (if any).
- * Doing unconditionally saves a cmp-n-branch; for already unused
- * ASID slot, the value was/remains NULL
+ * Move to new ASID if it was not from current alloc-cycle/generation.
+ * This is done by ensuring that the generation bits in both mm->ASID
+ * and cpu's ASID counter are exactly same.
+ *
+ * Note: Callers needing new ASID unconditionally, independent of
+ * generation, e.g. local_flush_tlb_mm() for forking parent,
+ * first need to destroy the context, setting it to invalid
+ * value.
*/
- asid_mm_map[mm->context.asid] = (struct mm_struct *)NULL;
+ if (!((asid_mm(mm, cpu) ^ asid_cpu(cpu)) & MM_CTXT_CYCLE_MASK))
+ goto set_hw;
- /* move to new ASID */
- if (++asid_cache > MAX_ASID) { /* ASID roll-over */
- asid_cache = FIRST_ASID;
- flush_tlb_all();
- }
+ /* move to new ASID and handle rollover */
+ if (unlikely(!(++asid_cpu(cpu) & MM_CTXT_ASID_MASK))) {
- /*
- * Is next ASID already owned by some-one else (we are stealing it).
- * If so, let the orig owner be aware of this, so when it runs, it
- * asks for a brand new ASID. This would only happen for a long-lived
- * task with ASID from prev allocation cycle (before ASID roll-over).
- *
- * This might look wrong - if we are re-using some other task's ASID,
- * won't we use it's stale TLB entries too. Actually switch_mm( ) takes
- * care of such a case: it ensures that task with ASID from prev alloc
- * cycle, when scheduled will refresh it's ASID: see switch_mm( ) below
- * The stealing scenario described here will only happen if that task
- * didn't get a chance to refresh it's ASID - implying stale entries
- * won't exist.
- */
- prev_owner = asid_mm_map[asid_cache];
- if (prev_owner)
- prev_owner->context.asid = NO_ASID;
+ local_flush_tlb_all();
+
+ /*
+ * Above checke for rollover of 8 bit ASID in 32 bit container.
+ * If the container itself wrapped around, set it to a non zero
+ * "generation" to distinguish from no context
+ */
+ if (!asid_cpu(cpu))
+ asid_cpu(cpu) = MM_CTXT_FIRST_CYCLE;
+ }
/* Assign new ASID to tsk */
- asid_mm_map[asid_cache] = mm;
- mm->context.asid = asid_cache;
-
-#ifdef CONFIG_ARC_TLB_DBG
- pr_info("ARC_TLB_DBG: NewMM=0x%x OldMM=0x%x task_struct=0x%x Task: %s,"
- " pid:%u, assigned asid:%lu\n",
- (unsigned int)mm, (unsigned int)prev_owner,
- (unsigned int)(mm->context.tsk), (mm->context.tsk)->comm,
- (mm->context.tsk)->pid, mm->context.asid);
-#endif
+ asid_mm(mm, cpu) = asid_cpu(cpu);
- write_aux_reg(ARC_REG_PID, asid_cache | MMU_ENABLE);
+set_hw:
+ write_aux_reg(ARC_REG_PID, hw_pid(mm, cpu) | MMU_ENABLE);
local_irq_restore(flags);
}
@@ -134,59 +107,61 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
static inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
- mm->context.asid = NO_ASID;
-#ifdef CONFIG_ARC_TLB_DBG
- mm->context.tsk = tsk;
-#endif
+ int i;
+
+ for_each_possible_cpu(i)
+ asid_mm(mm, i) = MM_CTXT_NO_ASID;
+
return 0;
}
+static inline void destroy_context(struct mm_struct *mm)
+{
+ unsigned long flags;
+
+ /* Needed to elide CONFIG_DEBUG_PREEMPT warning */
+ local_irq_save(flags);
+ asid_mm(mm, smp_processor_id()) = MM_CTXT_NO_ASID;
+ local_irq_restore(flags);
+}
+
/* Prepare the MMU for task: setup PID reg with allocated ASID
If task doesn't have an ASID (never alloc or stolen, get a new ASID)
*/
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
+ const int cpu = smp_processor_id();
+
+ /*
+ * Note that the mm_cpumask is "aggregating" only, we don't clear it
+ * for the switched-out task, unlike some other arches.
+ * It is used to enlist cpus for sending TLB flush IPIs and not sending
+ * it to CPUs where a task once ran-on, could cause stale TLB entry
+ * re-use, specially for a multi-threaded task.
+ * e.g. T1 runs on C1, migrates to C3. T2 running on C2 munmaps.
+ * For a non-aggregating mm_cpumask, IPI not sent C1, and if T1
+ * were to re-migrate to C1, it could access the unmapped region
+ * via any existing stale TLB entries.
+ */
+ cpumask_set_cpu(cpu, mm_cpumask(next));
+
#ifndef CONFIG_SMP
/* PGD cached in MMU reg to avoid 3 mem lookups: task->mm->pgd */
write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
#endif
- /*
- * Get a new ASID if task doesn't have a valid one. Possible when
- * -task never had an ASID (fresh after fork)
- * -it's ASID was stolen - past an ASID roll-over.
- * -There's a third obscure scenario (if this task is running for the
- * first time afer an ASID rollover), where despite having a valid
- * ASID, we force a get for new ASID - see comments at top.
- *
- * Both the non-alloc scenario and first-use-after-rollover can be
- * detected using the single condition below: NO_ASID = 256
- * while asid_cache is always a valid ASID value (0-255).
- */
- if (next->context.asid > asid_cache) {
- get_new_mmu_context(next);
- } else {
- /*
- * XXX: This will never happen given the chks above
- * BUG_ON(next->context.asid > MAX_ASID);
- */
- write_aux_reg(ARC_REG_PID, next->context.asid | MMU_ENABLE);
- }
-
+ get_new_mmu_context(next);
}
-static inline void destroy_context(struct mm_struct *mm)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- asid_mm_map[mm->context.asid] = NULL;
- mm->context.asid = NO_ASID;
-
- local_irq_restore(flags);
-}
+/*
+ * Called at the time of execve() to get a new ASID
+ * Note the subtlety here: get_new_mmu_context() behaves differently here
+ * vs. in switch_mm(). Here it always returns a new ASID, because mm has
+ * an unallocated "initial" value, while in latter, it moves to a new ASID,
+ * only if it was unallocated
+ */
+#define activate_mm(prev, next) switch_mm(prev, next, NULL)
/* it seemed that deactivate_mm( ) is a reasonable place to do book-keeping
* for retiring-mm. However destroy_context( ) still needs to do that because
@@ -197,17 +172,6 @@ static inline void destroy_context(struct mm_struct *mm)
*/
#define deactivate_mm(tsk, mm) do { } while (0)
-static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-#ifndef CONFIG_SMP
- write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
-#endif
-
- /* Unconditionally get a new ASID */
- get_new_mmu_context(next);
-
-}
-
#define enter_lazy_tlb(mm, tsk)
#endif /* __ASM_ARC_MMU_CONTEXT_H */
diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
index bdf54610455..9c8aa41e45c 100644
--- a/arch/arc/include/asm/page.h
+++ b/arch/arc/include/asm/page.h
@@ -16,12 +16,17 @@
#define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
#define free_user_page(page, addr) free_page(addr)
-/* TBD: for now don't worry about VIPT D$ aliasing */
#define clear_page(paddr) memset((paddr), 0, PAGE_SIZE)
#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
-#define clear_user_page(addr, vaddr, pg) clear_page(addr)
-#define copy_user_page(vto, vfrom, vaddr, pg) copy_page(vto, vfrom)
+struct vm_area_struct;
+struct page;
+
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long u_vaddr, struct vm_area_struct *vma);
+void clear_user_page(void *to, unsigned long u_vaddr, struct page *page);
#undef STRICT_MM_TYPECHECKS
@@ -91,13 +96,8 @@ typedef unsigned long pgtable_t;
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-/* Default Permissions for page, used in mmap.c */
-#ifdef CONFIG_ARC_STACK_NONEXEC
+/* Default Permissions for stack/heaps pages (Non Executable) */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE)
-#else
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#endif
#define WANT_PAGE_VIRTUAL 1
diff --git a/arch/arc/include/asm/perf_event.h b/arch/arc/include/asm/perf_event.h
index 115ad96480e..cbf755e32a0 100644
--- a/arch/arc/include/asm/perf_event.h
+++ b/arch/arc/include/asm/perf_event.h
@@ -1,5 +1,7 @@
/*
- * Copyright (C) 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ * Linux performance counter support for ARC
+ *
+ * Copyright (C) 2011-2013 Synopsys, Inc. (www.synopsys.com)
*
* 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
@@ -10,4 +12,204 @@
#ifndef __ASM_PERF_EVENT_H
#define __ASM_PERF_EVENT_H
+/* real maximum varies per CPU, this is the maximum supported by the driver */
+#define ARC_PMU_MAX_HWEVENTS 64
+
+#define ARC_REG_CC_BUILD 0xF6
+#define ARC_REG_CC_INDEX 0x240
+#define ARC_REG_CC_NAME0 0x241
+#define ARC_REG_CC_NAME1 0x242
+
+#define ARC_REG_PCT_BUILD 0xF5
+#define ARC_REG_PCT_COUNTL 0x250
+#define ARC_REG_PCT_COUNTH 0x251
+#define ARC_REG_PCT_SNAPL 0x252
+#define ARC_REG_PCT_SNAPH 0x253
+#define ARC_REG_PCT_CONFIG 0x254
+#define ARC_REG_PCT_CONTROL 0x255
+#define ARC_REG_PCT_INDEX 0x256
+
+#define ARC_REG_PCT_CONTROL_CC (1 << 16) /* clear counts */
+#define ARC_REG_PCT_CONTROL_SN (1 << 17) /* snapshot */
+
+struct arc_reg_pct_build {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int m:8, c:8, r:6, s:2, v:8;
+#else
+ unsigned int v:8, s:2, r:6, c:8, m:8;
+#endif
+};
+
+struct arc_reg_cc_build {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int c:16, r:8, v:8;
+#else
+ unsigned int v:8, r:8, c:16;
+#endif
+};
+
+#define PERF_COUNT_ARC_DCLM (PERF_COUNT_HW_MAX + 0)
+#define PERF_COUNT_ARC_DCSM (PERF_COUNT_HW_MAX + 1)
+#define PERF_COUNT_ARC_ICM (PERF_COUNT_HW_MAX + 2)
+#define PERF_COUNT_ARC_BPOK (PERF_COUNT_HW_MAX + 3)
+#define PERF_COUNT_ARC_EDTLB (PERF_COUNT_HW_MAX + 4)
+#define PERF_COUNT_ARC_EITLB (PERF_COUNT_HW_MAX + 5)
+#define PERF_COUNT_ARC_HW_MAX (PERF_COUNT_HW_MAX + 6)
+
+/*
+ * The "generalized" performance events seem to really be a copy
+ * of the available events on x86 processors; the mapping to ARC
+ * events is not always possible 1-to-1. Fortunately, there doesn't
+ * seem to be an exact definition for these events, so we can cheat
+ * a bit where necessary.
+ *
+ * In particular, the following PERF events may behave a bit differently
+ * compared to other architectures:
+ *
+ * PERF_COUNT_HW_CPU_CYCLES
+ * Cycles not in halted state
+ *
+ * PERF_COUNT_HW_REF_CPU_CYCLES
+ * Reference cycles not in halted state, same as PERF_COUNT_HW_CPU_CYCLES
+ * for now as we don't do Dynamic Voltage/Frequency Scaling (yet)
+ *
+ * PERF_COUNT_HW_BUS_CYCLES
+ * Unclear what this means, Intel uses 0x013c, which according to
+ * their datasheet means "unhalted reference cycles". It sounds similar
+ * to PERF_COUNT_HW_REF_CPU_CYCLES, and we use the same counter for it.
+ *
+ * PERF_COUNT_HW_STALLED_CYCLES_BACKEND
+ * PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
+ * The ARC 700 can either measure stalls per pipeline stage, or all stalls
+ * combined; for now we assign all stalls to STALLED_CYCLES_BACKEND
+ * and all pipeline flushes (e.g. caused by mispredicts, etc.) to
+ * STALLED_CYCLES_FRONTEND.
+ *
+ * We could start multiple performance counters and combine everything
+ * afterwards, but that makes it complicated.
+ *
+ * Note that I$ cache misses aren't counted by either of the two!
+ */
+
+static const char * const arc_pmu_ev_hw_map[] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = "crun",
+ [PERF_COUNT_HW_REF_CPU_CYCLES] = "crun",
+ [PERF_COUNT_HW_BUS_CYCLES] = "crun",
+ [PERF_COUNT_HW_INSTRUCTIONS] = "iall",
+ [PERF_COUNT_HW_BRANCH_MISSES] = "bpfail",
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmp",
+ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = "bflush",
+ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = "bstall",
+ [PERF_COUNT_ARC_DCLM] = "dclm",
+ [PERF_COUNT_ARC_DCSM] = "dcsm",
+ [PERF_COUNT_ARC_ICM] = "icm",
+ [PERF_COUNT_ARC_BPOK] = "bpok",
+ [PERF_COUNT_ARC_EDTLB] = "edtlb",
+ [PERF_COUNT_ARC_EITLB] = "eitlb",
+};
+
+#define C(_x) PERF_COUNT_HW_CACHE_##_x
+#define CACHE_OP_UNSUPPORTED 0xffff
+
+static const unsigned arc_pmu_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+ [C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = PERF_COUNT_ARC_DCLM,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = PERF_COUNT_ARC_DCSM,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = PERF_COUNT_ARC_ICM,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = PERF_COUNT_ARC_EDTLB,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = PERF_COUNT_ARC_EITLB,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
+ [C(RESULT_MISS)] = PERF_COUNT_HW_BRANCH_MISSES,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+ [C(NODE)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
+ },
+ },
+};
+
#endif /* __ASM_PERF_EVENT_H */
diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h
index 36a9f20c21a..81208bfd9dc 100644
--- a/arch/arc/include/asm/pgalloc.h
+++ b/arch/arc/include/asm/pgalloc.h
@@ -105,11 +105,16 @@ static inline pgtable_t
pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
pgtable_t pte_pg;
+ struct page *page;
pte_pg = __get_free_pages(GFP_KERNEL | __GFP_REPEAT, __get_order_pte());
- if (pte_pg) {
- memzero((void *)pte_pg, PTRS_PER_PTE * 4);
- pgtable_page_ctor(virt_to_page(pte_pg));
+ if (!pte_pg)
+ return 0;
+ memzero((void *)pte_pg, PTRS_PER_PTE * 4);
+ page = virt_to_page(pte_pg);
+ if (!pgtable_page_ctor(page)) {
+ __free_page(page);
+ return 0;
}
return pte_pg;
diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h
index b7e36684c09..6b0b7f7ef78 100644
--- a/arch/arc/include/asm/pgtable.h
+++ b/arch/arc/include/asm/pgtable.h
@@ -60,40 +60,29 @@
#define _PAGE_EXECUTE (1<<3) /* Page has user execute perm (H) */
#define _PAGE_WRITE (1<<4) /* Page has user write perm (H) */
#define _PAGE_READ (1<<5) /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE (1<<6) /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE (1<<7) /* Page has kernel write perm (H) */
-#define _PAGE_K_READ (1<<8) /* Page has kernel perm (H) */
-#define _PAGE_GLOBAL (1<<9) /* Page is global (H) */
-#define _PAGE_MODIFIED (1<<10) /* Page modified (dirty) (S) */
-#define _PAGE_FILE (1<<10) /* page cache/ swap (S) */
-#define _PAGE_PRESENT (1<<11) /* TLB entry is valid (H) */
+#define _PAGE_MODIFIED (1<<6) /* Page modified (dirty) (S) */
+#define _PAGE_FILE (1<<7) /* page cache/ swap (S) */
+#define _PAGE_GLOBAL (1<<8) /* Page is global (H) */
+#define _PAGE_PRESENT (1<<10) /* TLB entry is valid (H) */
-#else
+#else /* MMU v3 onwards */
-/* PD1 */
#define _PAGE_CACHEABLE (1<<0) /* Page is cached (H) */
#define _PAGE_EXECUTE (1<<1) /* Page has user execute perm (H) */
#define _PAGE_WRITE (1<<2) /* Page has user write perm (H) */
#define _PAGE_READ (1<<3) /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE (1<<4) /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE (1<<5) /* Page has kernel write perm (H) */
-#define _PAGE_K_READ (1<<6) /* Page has kernel perm (H) */
-#define _PAGE_ACCESSED (1<<7) /* Page is accessed (S) */
-
-/* PD0 */
+#define _PAGE_ACCESSED (1<<4) /* Page is accessed (S) */
+#define _PAGE_MODIFIED (1<<5) /* Page modified (dirty) (S) */
+#define _PAGE_FILE (1<<6) /* page cache/ swap (S) */
#define _PAGE_GLOBAL (1<<8) /* Page is global (H) */
#define _PAGE_PRESENT (1<<9) /* TLB entry is valid (H) */
-#define _PAGE_SHARED_CODE (1<<10) /* Shared Code page with cmn vaddr
+#define _PAGE_SHARED_CODE (1<<11) /* Shared Code page with cmn vaddr
usable for shared TLB entries (H) */
-
-#define _PAGE_MODIFIED (1<<11) /* Page modified (dirty) (S) */
-#define _PAGE_FILE (1<<12) /* page cache/ swap (S) */
-
-#define _PAGE_SHARED_CODE_H (1<<31) /* Hardware counterpart of above */
#endif
-/* Kernel allowed all permissions for all pages */
-#define _K_PAGE_PERMS (_PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
+/* vmalloc permissions */
+#define _K_PAGE_PERMS (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ | \
+ _PAGE_GLOBAL | _PAGE_PRESENT)
#ifdef CONFIG_ARC_CACHE_PAGES
#define _PAGE_DEF_CACHEABLE _PAGE_CACHEABLE
@@ -106,7 +95,7 @@
* -by default cached, unless config otherwise
* -present in memory
*/
-#define ___DEF (_PAGE_PRESENT | _K_PAGE_PERMS | _PAGE_DEF_CACHEABLE)
+#define ___DEF (_PAGE_PRESENT | _PAGE_DEF_CACHEABLE)
/* Set of bits not changed in pte_modify */
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED)
@@ -121,15 +110,19 @@
#define PAGE_SHARED PAGE_U_W_R
-/* While kernel runs out of unstrslated space, vmalloc/modules use a chunk of
- * kernel vaddr space - visible in all addr spaces, but kernel mode only
+/* While kernel runs out of unstranslated space, vmalloc/modules use a chunk of
+ * user vaddr space - visible in all addr spaces, but kernel mode only
* Thus Global, all-kernel-access, no-user-access, cached
*/
-#define PAGE_KERNEL __pgprot(___DEF | _PAGE_GLOBAL)
+#define PAGE_KERNEL __pgprot(_K_PAGE_PERMS | _PAGE_DEF_CACHEABLE)
/* ioremap */
-#define PAGE_KERNEL_NO_CACHE __pgprot(_PAGE_PRESENT | _K_PAGE_PERMS | \
- _PAGE_GLOBAL)
+#define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS)
+
+/* Masks for actual TLB "PD"s */
+#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT)
+#define PTE_BITS_RWX (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ)
+#define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE)
/**************************************************************************
* Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
@@ -390,11 +383,11 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
-#define io_remap_pfn_range(vma, from, pfn, size, prot) \
- remap_pfn_range(vma, from, pfn, size, prot)
-
#include <asm-generic/pgtable.h>
+/* to cope with aliasing VIPT cache */
+#define HAVE_ARCH_UNMAPPED_AREA
+
/*
* No page table caches to initialise
*/
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index 5f26b2c1cba..d99f9b37cd1 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -18,7 +18,7 @@
#ifndef __ASSEMBLY__
-#include <asm/arcregs.h> /* for STATUS_E1_MASK et all */
+#include <asm/ptrace.h>
/* Arch specific stuff which needs to be saved per task.
* However these items are not so important so as to earn a place in
@@ -28,10 +28,6 @@ struct thread_struct {
unsigned long ksp; /* kernel mode stack pointer */
unsigned long callee_reg; /* pointer to callee regs */
unsigned long fault_address; /* dbls as brkpt holder as well */
- unsigned long cause_code; /* Exception Cause Code (ECR) */
-#ifdef CONFIG_ARC_CURR_IN_REG
- unsigned long user_r25;
-#endif
#ifdef CONFIG_ARC_FPU_SAVE_RESTORE
struct arc_fpu fpu;
#endif
@@ -44,15 +40,13 @@ struct thread_struct {
/* Forward declaration, a strange C thing */
struct task_struct;
-/*
- * Return saved PC of a blocked thread.
- */
+/* Return saved PC of a blocked thread */
unsigned long thread_saved_pc(struct task_struct *t);
#define task_pt_regs(p) \
- ((struct pt_regs *)(THREAD_SIZE - 4 + (void *)task_stack_page(p)) - 1)
+ ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
-/* Free all resources held by a thread. */
+/* Free all resources held by a thread */
#define release_thread(thread) do { } while (0)
/* Prepare to copy thread state - unlazy all lazy status */
@@ -75,32 +69,18 @@ unsigned long thread_saved_pc(struct task_struct *t);
/*
* Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
- * These can't be derived from pt_regs as that would give correp user-mode val
+ * Look in process.c for details of kernel stack layout
*/
#define KSTK_ESP(tsk) (tsk->thread.ksp)
-#define KSTK_BLINK(tsk) (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1+1)*4)))
-#define KSTK_FP(tsk) (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1)*4)))
-/*
- * Do necessary setup to start up a newly executed thread.
- *
- * E1,E2 so that Interrupts are enabled in user mode
- * L set, so Loop inhibited to begin with
- * lp_start and lp_end seeded with bogus non-zero values so to easily catch
- * the ARC700 sr to lp_start hardware bug
- */
-#define start_thread(_regs, _pc, _usp) \
-do { \
- set_fs(USER_DS); /* reads from user space */ \
- (_regs)->ret = (_pc); \
- /* Interrupts enabled in User Mode */ \
- (_regs)->status32 = STATUS_U_MASK | STATUS_L_MASK \
- | STATUS_E1_MASK | STATUS_E2_MASK; \
- (_regs)->sp = (_usp); \
- /* bogus seed values for debugging */ \
- (_regs)->lp_start = 0x10; \
- (_regs)->lp_end = 0x80; \
-} while (0)
+#define KSTK_REG(tsk, off) (*((unsigned int *)(KSTK_ESP(tsk) + \
+ sizeof(struct callee_regs) + off)))
+
+#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
+#define KSTK_FP(tsk) KSTK_REG(tsk, 0)
+
+extern void start_thread(struct pt_regs * regs, unsigned long pc,
+ unsigned long usp);
extern unsigned int get_wchan(struct task_struct *p);
diff --git a/arch/arc/include/asm/prom.h b/arch/arc/include/asm/prom.h
deleted file mode 100644
index 692d0d0789a..00000000000
--- a/arch/arc/include/asm/prom.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
- *
- * 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 _ASM_ARC_PROM_H_
-#define _ASM_ARC_PROM_H_
-
-#define HAVE_ARCH_DEVTREE_FIXUPS
-
-#endif
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 8ae783d20a8..1bfeec2c055 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -17,68 +17,50 @@
/* THE pt_regs: Defines how regs are saved during entry into kernel */
struct pt_regs {
- /*
- * 1 word gutter after reg-file has been saved
- * Technically not needed, Since SP always points to a "full" location
- * (vs. "empty"). But pt_regs is shared with tools....
- */
- long res;
/* Real registers */
long bta; /* bta_l1, bta_l2, erbta */
- long lp_start;
- long lp_end;
- long lp_count;
+
+ long lp_start, lp_end, lp_count;
+
long status32; /* status32_l1, status32_l2, erstatus */
long ret; /* ilink1, ilink2 or eret */
long blink;
long fp;
long r26; /* gp */
- long r12;
- long r11;
- long r10;
- long r9;
- long r8;
- long r7;
- long r6;
- long r5;
- long r4;
- long r3;
- long r2;
- long r1;
- long r0;
+
+ long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+
long sp; /* user/kernel sp depending on where we came from */
long orig_r0;
- /*to distinguish bet excp, syscall, irq */
+ /*
+ * To distinguish bet excp, syscall, irq
+ * For traps and exceptions, Exception Cause Register.
+ * ECR: <00> <VV> <CC> <PP>
+ * Last word used by Linux for extra state mgmt (syscall-restart)
+ * For interrupts, use artificial ECR values to note current prio-level
+ */
union {
+ struct {
#ifdef CONFIG_CPU_BIG_ENDIAN
- /* so that assembly code is same for LE/BE */
- unsigned long orig_r8:16, event:16;
+ unsigned long state:8, ecr_vec:8,
+ ecr_cause:8, ecr_param:8;
#else
- unsigned long event:16, orig_r8:16;
+ unsigned long ecr_param:8, ecr_cause:8,
+ ecr_vec:8, state:8;
#endif
- long orig_r8_word;
+ };
+ unsigned long event;
};
+
+ long user_r25;
};
/* Callee saved registers - need to be saved only when you are scheduled out */
struct callee_regs {
- long res; /* Again this is not needed */
- long r25;
- long r24;
- long r23;
- long r22;
- long r21;
- long r20;
- long r19;
- long r18;
- long r17;
- long r16;
- long r15;
- long r14;
- long r13;
+ long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
};
#define instruction_pointer(regs) ((regs)->ret)
@@ -99,18 +81,20 @@ struct callee_regs {
/* return 1 if PC in delay slot */
#define delay_mode(regs) ((regs->status32 & STATUS_DE_MASK) == STATUS_DE_MASK)
-#define in_syscall(regs) (regs->event & orig_r8_IS_SCALL)
-#define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT)
+#define in_syscall(regs) ((regs->ecr_vec == ECR_V_TRAP) && !regs->ecr_param)
+#define in_brkpt_trap(regs) ((regs->ecr_vec == ECR_V_TRAP) && regs->ecr_param)
-#define syscall_wont_restart(regs) (regs->event |= orig_r8_IS_SCALL_RESTARTED)
-#define syscall_restartable(regs) !(regs->event & orig_r8_IS_SCALL_RESTARTED)
+#define STATE_SCALL_RESTARTED 0x01
+
+#define syscall_wont_restart(reg) (reg->state |= STATE_SCALL_RESTARTED)
+#define syscall_restartable(reg) !(reg->state & STATE_SCALL_RESTARTED)
#define current_pt_regs() \
({ \
/* open-coded current_thread_info() */ \
register unsigned long sp asm ("sp"); \
unsigned long pg_start = (sp & ~(THREAD_SIZE - 1)); \
- (struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1; \
+ (struct pt_regs *)(pg_start + THREAD_SIZE) - 1; \
})
static inline long regs_return_value(struct pt_regs *regs)
@@ -120,11 +104,4 @@ static inline long regs_return_value(struct pt_regs *regs)
#endif /* !__ASSEMBLY__ */
-#define orig_r8_IS_SCALL 0x0001
-#define orig_r8_IS_SCALL_RESTARTED 0x0002
-#define orig_r8_IS_BRKPT 0x0004
-#define orig_r8_IS_EXCPN 0x0004
-#define orig_r8_IS_IRQ1 0x0010
-#define orig_r8_IS_IRQ2 0x0020
-
#endif /* __ASM_PTRACE_H */
diff --git a/arch/arc/include/asm/sections.h b/arch/arc/include/asm/sections.h
index 6fc1159dfef..09db952e14b 100644
--- a/arch/arc/include/asm/sections.h
+++ b/arch/arc/include/asm/sections.h
@@ -11,8 +11,6 @@
#include <asm-generic/sections.h>
-extern char _int_vec_base_lds[];
extern char __arc_dccm_base[];
-extern char __dtb_start[];
#endif
diff --git a/arch/arc/include/asm/serial.h b/arch/arc/include/asm/serial.h
index 4dff5a1e412..602b0970a76 100644
--- a/arch/arc/include/asm/serial.h
+++ b/arch/arc/include/asm/serial.h
@@ -22,4 +22,14 @@
#define BASE_BAUD (arc_get_core_freq() / 16)
+/*
+ * This is definitely going to break early 8250 consoles on multi-platform
+ * images but hey, it won't add any code complexity for a debug feature of
+ * one broken driver.
+ */
+#ifdef CONFIG_ARC_PLAT_TB10X
+#undef BASE_BAUD
+#define BASE_BAUD (arc_get_core_freq() / 16 / 3)
+#endif
+
#endif /* _ASM_ARC_SERIAL_H */
diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h
index 229e5068149..e10f8cef56a 100644
--- a/arch/arc/include/asm/setup.h
+++ b/arch/arc/include/asm/setup.h
@@ -31,7 +31,7 @@ struct cpuinfo_data {
extern int root_mountflags, end_mem;
extern int running_on_hw;
-void __init setup_processor(void);
+void setup_processor(void);
void __init setup_arch_memory(void);
#endif /* __ASMARC_SETUP_H */
diff --git a/arch/arc/include/asm/shmparam.h b/arch/arc/include/asm/shmparam.h
new file mode 100644
index 00000000000..fffeecc0427
--- /dev/null
+++ b/arch/arc/include/asm/shmparam.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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 __ARC_ASM_SHMPARAM_H
+#define __ARC_ASM_SHMPARAM_H
+
+/* Handle upto 2 cache bins */
+#define SHMLBA (2 * PAGE_SIZE)
+
+/* Enforce SHMLBA in shmat */
+#define __ARCH_FORCE_SHMLBA
+
+#endif
diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h
index c4fb211dcd2..5d06eee43ea 100644
--- a/arch/arc/include/asm/smp.h
+++ b/arch/arc/include/asm/smp.h
@@ -30,7 +30,7 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
* APIs provided by arch SMP code to rest of arch code
*/
extern void __init smp_init_cpus(void);
-extern void __init first_lines_of_secondary(void);
+extern void first_lines_of_secondary(void);
extern const char *arc_platform_smp_cpuinfo(void);
/*
@@ -46,14 +46,14 @@ extern int smp_ipi_irq_setup(int cpu, int irq);
*
* @info: SoC SMP specific info for /proc/cpuinfo etc
* @cpu_kick: For Master to kickstart a cpu (optionally at a PC)
- * @ipi_send: To send IPI to a @cpumask
- * @ips_clear: To clear IPI received by @cpu at @irq
+ * @ipi_send: To send IPI to a @cpu
+ * @ips_clear: To clear IPI received at @irq
*/
struct plat_smp_ops {
const char *info;
void (*cpu_kick)(int cpu, unsigned long pc);
- void (*ipi_send)(void *callmap);
- void (*ipi_clear)(int cpu, int irq);
+ void (*ipi_send)(int cpu);
+ void (*ipi_clear)(int irq);
};
/* TBD: stop exporting it for direct population by platform */
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index f158197ac5b..b6a8c2dfbe6 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -45,7 +45,14 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
- lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+ unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+ __asm__ __volatile__(
+ " ex %0, [%1] \n"
+ : "+r" (tmp)
+ : "r"(&(lock->slock))
+ : "memory");
+
smp_mb();
}
diff --git a/arch/arc/include/asm/spinlock_types.h b/arch/arc/include/asm/spinlock_types.h
index 8276bfd6170..662627ced4f 100644
--- a/arch/arc/include/asm/spinlock_types.h
+++ b/arch/arc/include/asm/spinlock_types.h
@@ -20,9 +20,9 @@ typedef struct {
#define __ARCH_SPIN_LOCK_LOCKED { __ARCH_SPIN_LOCK_LOCKED__ }
/*
- * Unlocked: 0x01_00_00_00
- * Read lock(s): 0x00_FF_00_00 to say 0x01
- * Write lock: 0x0, but only possible if prior value "unlocked" 0x0100_0000
+ * Unlocked : 0x0100_0000
+ * Read lock(s) : 0x00FF_FFFF to 0x01 (Multiple Readers decrement it)
+ * Write lock : 0x0, but only if prior value is "unlocked" 0x0100_0000
*/
typedef struct {
volatile unsigned int counter;
diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 33ab3048e9b..29de0980430 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -18,7 +18,7 @@ static inline long
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
if (user_mode(regs) && in_syscall(regs))
- return regs->orig_r8;
+ return regs->r8;
else
return -1;
}
@@ -26,8 +26,7 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
static inline void
syscall_rollback(struct task_struct *task, struct pt_regs *regs)
{
- /* XXX: I can't fathom how pt_regs->r8 will be clobbered ? */
- regs->r8 = regs->orig_r8;
+ regs->r0 = regs->orig_r0;
}
static inline long
diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h
index e53a5340ba4..dd785befe7f 100644
--- a/arch/arc/include/asm/syscalls.h
+++ b/arch/arc/include/asm/syscalls.h
@@ -16,8 +16,6 @@
#include <linux/types.h>
int sys_clone_wrapper(int, int, int, int, int);
-int sys_fork_wrapper(void);
-int sys_vfork_wrapper(void);
int sys_cacheflush(uint32_t, uint32_t uint32_t);
int sys_arc_settls(void *);
int sys_arc_gettls(void);
diff --git a/arch/arc/include/asm/thread_info.h b/arch/arc/include/asm/thread_info.h
index 2d50a4cdd7f..45be2167201 100644
--- a/arch/arc/include/asm/thread_info.h
+++ b/arch/arc/include/asm/thread_info.h
@@ -80,8 +80,6 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void)
#endif /* !__ASSEMBLY__ */
-#define PREEMPT_ACTIVE 0x10000000
-
/*
* thread information flags
* - these are process state flags that various assembly files may need to
diff --git a/arch/arc/include/asm/tlb-mmu1.h b/arch/arc/include/asm/tlb-mmu1.h
index a5ff961b1ef..8a1ec96012a 100644
--- a/arch/arc/include/asm/tlb-mmu1.h
+++ b/arch/arc/include/asm/tlb-mmu1.h
@@ -9,9 +9,9 @@
#ifndef __ASM_TLB_MMU_V1_H__
#define __ASM_TLB_MMU_V1_H__
-#if defined(__ASSEMBLY__) && defined(CONFIG_ARC_MMU_VER == 1)
+#include <asm/mmu.h>
-#include <asm/tlb.h>
+#if defined(__ASSEMBLY__) && (CONFIG_ARC_MMU_VER == 1)
.macro TLB_WRITE_HEURISTICS
diff --git a/arch/arc/include/asm/tlb.h b/arch/arc/include/asm/tlb.h
index 3eb2ce0bdfa..a9db5f62aaf 100644
--- a/arch/arc/include/asm/tlb.h
+++ b/arch/arc/include/asm/tlb.h
@@ -9,50 +9,39 @@
#ifndef _ASM_ARC_TLB_H
#define _ASM_ARC_TLB_H
-#ifdef __KERNEL__
-
-#include <asm/pgtable.h>
-
-/* Masks for actual TLB "PD"s */
-#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT)
-#define PTE_BITS_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE | \
- _PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ | \
- _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
-
-#ifndef __ASSEMBLY__
-
-#define tlb_flush(tlb) local_flush_tlb_mm((tlb)->mm)
+#define tlb_flush(tlb) \
+do { \
+ if (tlb->fullmm) \
+ flush_tlb_mm((tlb)->mm); \
+} while (0)
/*
* This pair is called at time of munmap/exit to flush cache and TLB entries
* for mappings being torn down.
- * 1) cache-flush part -implemented via tlb_start_vma( ) can be NOP (for now)
- * as we don't support aliasing configs in our VIPT D$.
- * 2) tlb-flush part - implemted via tlb_end_vma( ) can be NOP as well-
- * albiet for difft reasons - its better handled by moving to new ASID
+ * 1) cache-flush part -implemented via tlb_start_vma( ) for VIPT aliasing D$
+ * 2) tlb-flush part - implemted via tlb_end_vma( ) flushes the TLB range
*
* Note, read http://lkml.org/lkml/2004/1/15/6
*/
+#ifndef CONFIG_ARC_CACHE_VIPT_ALIASING
#define tlb_start_vma(tlb, vma)
-#define tlb_end_vma(tlb, vma)
-
-#define __tlb_remove_tlb_entry(tlb, ptep, address)
-
-#include <linux/pagemap.h>
-#include <asm-generic/tlb.h>
-
-#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
#else
-#define tlb_paranoid_check(a, b)
+#define tlb_start_vma(tlb, vma) \
+do { \
+ if (!tlb->fullmm) \
+ flush_cache_range(vma, vma->vm_start, vma->vm_end); \
+} while(0)
#endif
-void arc_mmu_init(void);
-extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
-void __init read_decode_mmu_bcr(void);
+#define tlb_end_vma(tlb, vma) \
+do { \
+ if (!tlb->fullmm) \
+ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
+} while (0)
-#endif /* __ASSEMBLY__ */
+#define __tlb_remove_tlb_entry(tlb, ptep, address)
-#endif /* __KERNEL__ */
+#include <linux/pagemap.h>
+#include <asm-generic/tlb.h>
#endif /* _ASM_ARC_TLB_H */
diff --git a/arch/arc/include/asm/tlbflush.h b/arch/arc/include/asm/tlbflush.h
index b2f9bc7f68c..71c7b2e4b87 100644
--- a/arch/arc/include/asm/tlbflush.h
+++ b/arch/arc/include/asm/tlbflush.h
@@ -18,11 +18,18 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
void local_flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
-/* XXX: Revisit for SMP */
+#ifndef CONFIG_SMP
#define flush_tlb_range(vma, s, e) local_flush_tlb_range(vma, s, e)
#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page)
#define flush_tlb_kernel_range(s, e) local_flush_tlb_kernel_range(s, e)
#define flush_tlb_all() local_flush_tlb_all()
#define flush_tlb_mm(mm) local_flush_tlb_mm(mm)
-
+#else
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+#endif /* CONFIG_SMP */
#endif
diff --git a/arch/arc/include/asm/uaccess.h b/arch/arc/include/asm/uaccess.h
index 32420824375..30c9baffa96 100644
--- a/arch/arc/include/asm/uaccess.h
+++ b/arch/arc/include/asm/uaccess.h
@@ -43,7 +43,7 @@
* Because it essentially checks if buffer end is within limit and @len is
* non-ngeative, which implies that buffer start will be within limit too.
*
- * The reason for rewriting being, for majorit yof cases, @len is generally
+ * The reason for rewriting being, for majority of cases, @len is generally
* compile time constant, causing first sub-expression to be compile time
* subsumed.
*
@@ -53,7 +53,7 @@
*
*/
#define __user_ok(addr, sz) (((sz) <= TASK_SIZE) && \
- (((addr)+(sz)) <= get_fs()))
+ ((addr) <= (get_fs() - (sz))))
#define __access_ok(addr, sz) (unlikely(__kernel_ok) || \
likely(__user_ok((addr), (sz))))
diff --git a/arch/arc/include/asm/unaligned.h b/arch/arc/include/asm/unaligned.h
index 5dbe63f17b6..3e5f071bc00 100644
--- a/arch/arc/include/asm/unaligned.h
+++ b/arch/arc/include/asm/unaligned.h
@@ -16,13 +16,14 @@
#ifdef CONFIG_ARC_MISALIGN_ACCESS
int misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs);
+ struct callee_regs *cregs);
#else
static inline int
misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs)
+ struct callee_regs *cregs)
{
- return 0;
+ /* Not fixed */
+ return 1;
}
#endif
diff --git a/arch/arc/include/uapi/asm/Kbuild b/arch/arc/include/uapi/asm/Kbuild
index 18fefaea73f..f50d02df78d 100644
--- a/arch/arc/include/uapi/asm/Kbuild
+++ b/arch/arc/include/uapi/asm/Kbuild
@@ -2,11 +2,4 @@
include include/uapi/asm-generic/Kbuild.asm
header-y += elf.h
header-y += page.h
-header-y += setup.h
-header-y += byteorder.h
header-y += cachectl.h
-header-y += ptrace.h
-header-y += sigcontext.h
-header-y += signal.h
-header-y += swab.h
-header-y += unistd.h
diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h
index 6afa4f70207..76a7739aab1 100644
--- a/arch/arc/include/uapi/asm/ptrace.h
+++ b/arch/arc/include/uapi/asm/ptrace.h
@@ -11,6 +11,7 @@
#ifndef _UAPI__ASM_ARC_PTRACE_H
#define _UAPI__ASM_ARC_PTRACE_H
+#define PTRACE_GET_THREAD_AREA 25
#ifndef __ASSEMBLY__
/*
@@ -20,28 +21,31 @@
*
* This is to decouple pt_regs from user-space ABI, to be able to change it
* w/o affecting the ABI.
- * Although the layout (initial padding) is similar to pt_regs to have some
- * optimizations when copying pt_regs to/from user_regs_struct.
+ *
+ * The intermediate pad,pad2 are relics of initial layout based on pt_regs
+ * for optimizations when copying pt_regs to/from user_regs_struct.
+ * We no longer need them, but can't be changed as they are part of ABI now.
*
* Also, sigcontext only care about the scratch regs as that is what we really
- * save/restore for signal handling.
+ * save/restore for signal handling. However gdb also uses the same struct
+ * hence callee regs need to be in there too.
*/
struct user_regs_struct {
- struct scratch {
- long pad;
+ long pad;
+ struct {
long bta, lp_start, lp_end, lp_count;
long status32, ret, blink, fp, gp;
long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
long sp;
} scratch;
- struct callee {
- long pad;
+ long pad2;
+ struct {
long r25, r24, r23, r22, r21, r20;
long r19, r18, r17, r16, r15, r14, r13;
} callee;
long efa; /* break pt addr, for break points in delay slots */
- long stop_pc; /* give dbg stop_pc directly after checking orig_r8 */
+ long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */
};
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arc/include/uapi/asm/unistd.h b/arch/arc/include/uapi/asm/unistd.h
index 6f30484f34b..39e58d1cdf9 100644
--- a/arch/arc/include/uapi/asm/unistd.h
+++ b/arch/arc/include/uapi/asm/unistd.h
@@ -8,6 +8,13 @@
/******** no-legacy-syscalls-ABI *******/
+/*
+ * Non-typical guard macro to enable inclusion twice in ARCH sys.c
+ * That is how the Generic syscall wrapper generator works
+ */
+#if !defined(_UAPI_ASM_ARC_UNISTD_H) || defined(__SYSCALL)
+#define _UAPI_ASM_ARC_UNISTD_H
+
#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_VFORK
@@ -32,3 +39,7 @@ __SYSCALL(__NR_arc_gettls, sys_arc_gettls)
/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */
#define __NR_sysfs (__NR_arch_specific_syscall + 3)
__SYSCALL(__NR_sysfs, sys_sysfs)
+
+#undef __SYSCALL
+
+#endif
diff --git a/arch/arc/kernel/.gitignore b/arch/arc/kernel/.gitignore
new file mode 100644
index 00000000000..c5f676c3c22
--- /dev/null
+++ b/arch/arc/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index c242ef07ba7..8004b4fa646 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_ARC_MISALIGN_ACCESS) += unaligned.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_ARC_METAWARE_HLINK) += arc_hostlink.o
+obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o
CFLAGS_fpu.o += -mdpfp
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index 0dc148ebce7..6c3aa0edb9b 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -11,9 +11,9 @@
#include <linux/interrupt.h>
#include <linux/thread_info.h>
#include <linux/kbuild.h>
+#include <linux/ptrace.h>
#include <asm/hardirq.h>
#include <asm/page.h>
-#include <asm/ptrace.h>
int main(void)
{
@@ -24,9 +24,6 @@ int main(void)
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
-#ifdef CONFIG_ARC_CURR_IN_REG
- DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
-#endif
DEFINE(THREAD_FAULT_ADDR,
offsetof(struct thread_struct, fault_address));
@@ -49,7 +46,7 @@ int main(void)
BLANK();
DEFINE(PT_status32, offsetof(struct pt_regs, status32));
- DEFINE(PT_orig_r8, offsetof(struct pt_regs, orig_r8_word));
+ DEFINE(PT_event, offsetof(struct pt_regs, event));
DEFINE(PT_sp, offsetof(struct pt_regs, sp));
DEFINE(PT_r0, offsetof(struct pt_regs, r0));
DEFINE(PT_r1, offsetof(struct pt_regs, r1));
@@ -60,5 +57,7 @@ int main(void)
DEFINE(PT_r6, offsetof(struct pt_regs, r6));
DEFINE(PT_r7, offsetof(struct pt_regs, r7));
+ DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
+ DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
return 0;
}
diff --git a/arch/arc/kernel/clk.c b/arch/arc/kernel/clk.c
index 66ce0dc917f..10c7b0b5a07 100644
--- a/arch/arc/kernel/clk.c
+++ b/arch/arc/kernel/clk.c
@@ -8,7 +8,7 @@
#include <asm/clk.h>
-unsigned long core_freq = 800000000;
+unsigned long core_freq = 80000000;
/*
* As of now we default to device-tree provided clock
diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c
index 60844dac613..c14a5bea0c7 100644
--- a/arch/arc/kernel/ctx_sw.c
+++ b/arch/arc/kernel/ctx_sw.c
@@ -17,16 +17,14 @@
#include <asm/asm-offsets.h>
#include <linux/sched.h>
+#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
+
struct task_struct *__sched
__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
{
unsigned int tmp;
unsigned int prev = (unsigned int)prev_task;
unsigned int next = (unsigned int)next_task;
- int num_words_to_skip = 1;
-#ifdef CONFIG_ARC_CURR_IN_REG
- num_words_to_skip++;
-#endif
__asm__ __volatile__(
/* FP/BLINK save generated by gcc (standard function prologue */
@@ -44,11 +42,21 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
"st.a r24, [sp, -4] \n\t"
#ifndef CONFIG_ARC_CURR_IN_REG
"st.a r25, [sp, -4] \n\t"
+#else
+ "sub sp, sp, 4 \n\t" /* usual r25 placeholder */
#endif
- "sub sp, sp, %4 \n\t" /* create gutter at top */
/* set ksp of outgoing task in tsk->thread.ksp */
+#if KSP_WORD_OFF <= 255
"st.as sp, [%3, %1] \n\t"
+#else
+ /*
+ * Workaround for NR_CPUS=4k
+ * %1 is bigger than 255 (S9 offset for st.as)
+ */
+ "add2 r24, %3, %1 \n\t"
+ "st sp, [r24] \n\t"
+#endif
"sync \n\t"
@@ -76,10 +84,10 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
/* start loading it's CALLEE reg file */
- "add sp, sp, %4 \n\t" /* skip gutter at top */
-
#ifndef CONFIG_ARC_CURR_IN_REG
"ld.ab r25, [sp, 4] \n\t"
+#else
+ "add sp, sp, 4 \n\t"
#endif
"ld.ab r24, [sp, 4] \n\t"
"ld.ab r23, [sp, 4] \n\t"
@@ -100,8 +108,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
/* FP/BLINK restore generated by gcc (standard func epilogue */
: "=r"(tmp)
- : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev),
- "n"(num_words_to_skip * 4)
+ : "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
: "blink"
);
diff --git a/arch/arc/kernel/ctx_sw_asm.S b/arch/arc/kernel/ctx_sw_asm.S
index d8972345e4c..e248594097e 100644
--- a/arch/arc/kernel/ctx_sw_asm.S
+++ b/arch/arc/kernel/ctx_sw_asm.S
@@ -10,9 +10,11 @@
* -This is the more "natural" hand written assembler
*/
+#include <linux/linkage.h>
#include <asm/entry.h> /* For the SAVE_* macros */
#include <asm/asm-offsets.h>
-#include <asm/linkage.h>
+
+#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
;################### Low Level Context Switch ##########################
@@ -28,8 +30,13 @@ __switch_to:
SAVE_CALLEE_SAVED_KERNEL
/* Save the now KSP in task->thread.ksp */
- st.as sp, [r0, (TASK_THREAD + THREAD_KSP)/4]
-
+#if KSP_WORD_OFF <= 255
+ st.as sp, [r0, KSP_WORD_OFF]
+#else
+ /* Workaround for NR_CPUS=4k as ST.as can only take s9 offset */
+ add2 r24, r0, KSP_WORD_OFF
+ st sp, [r24]
+#endif
/*
* Return last task in r0 (return reg)
* On ARC, Return reg = First Arg reg = r0.
@@ -55,4 +62,4 @@ __switch_to:
ld.ab blink, [sp, 4]
j [blink]
-ARC_EXIT __switch_to
+END(__switch_to)
diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c
index bdee3a81205..fffdb5e41b2 100644
--- a/arch/arc/kernel/devtree.c
+++ b/arch/arc/kernel/devtree.c
@@ -14,14 +14,20 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
-#include <asm/prom.h>
#include <asm/clk.h>
#include <asm/mach_desc.h>
-/* called from unflatten_device_tree() to bootstrap devicetree itself */
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+static const void * __init arch_get_next_mach(const char *const **match)
{
- return __va(memblock_alloc(size, align));
+ static const struct machine_desc *mdesc = __arch_info_begin;
+ const struct machine_desc *m = mdesc;
+
+ if (m >= __arch_info_end)
+ return NULL;
+
+ mdesc++;
+ *match = m->dt_compat;
+ return m;
}
/**
@@ -31,93 +37,24 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
* If a dtb was passed to the kernel, then use it to choose the correct
* machine_desc and to setup the system.
*/
-struct machine_desc * __init setup_machine_fdt(void *dt)
+const struct machine_desc * __init setup_machine_fdt(void *dt)
{
- struct boot_param_header *devtree = dt;
- struct machine_desc *mdesc = NULL, *mdesc_best = NULL;
- unsigned int score, mdesc_score = ~1;
+ const struct machine_desc *mdesc;
unsigned long dt_root;
- const char *model, *compat;
- void *clk;
- char manufacturer[16];
- unsigned long len;
+ const void *clk;
+ int len;
- /* check device tree validity */
- if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)
+ if (!early_init_dt_scan(dt))
return NULL;
- initial_boot_params = devtree;
- dt_root = of_get_flat_dt_root();
-
- /*
- * The kernel could be multi-platform enabled, thus could have many
- * "baked-in" machine descriptors. Search thru all for the best
- * "compatible" string match.
- */
- for_each_machine_desc(mdesc) {
- score = of_flat_dt_match(dt_root, mdesc->dt_compat);
- if (score > 0 && score < mdesc_score) {
- mdesc_best = mdesc;
- mdesc_score = score;
- }
- }
- if (!mdesc_best) {
- const char *prop;
- long size;
-
- pr_err("\n unrecognized device tree list:\n[ ");
-
- prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
- if (prop) {
- while (size > 0) {
- printk("'%s' ", prop);
- size -= strlen(prop) + 1;
- prop += strlen(prop) + 1;
- }
- }
- printk("]\n\n");
-
+ mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach);
+ if (!mdesc)
machine_halt();
- }
-
- /* compat = "<manufacturer>,<model>" */
- compat = mdesc_best->dt_compat[0];
-
- model = strchr(compat, ',');
- if (model)
- model++;
-
- strlcpy(manufacturer, compat, model ? model - compat : strlen(compat));
-
- pr_info("Board \"%s\" from %s (Manufacturer)\n", model, manufacturer);
-
- /* Retrieve various information from the /chosen node */
- of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
-
- /* Initialize {size,address}-cells info */
- of_scan_flat_dt(early_init_dt_scan_root, NULL);
-
- /* Setup memory, calling early_init_dt_add_memory_arch */
- of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+ dt_root = of_get_flat_dt_root();
clk = of_get_flat_dt_prop(dt_root, "clock-frequency", &len);
if (clk)
arc_set_core_freq(of_read_ulong(clk, len/4));
- return mdesc_best;
-}
-
-/*
- * Copy the flattened DT out of .init since unflattening doesn't copy strings
- * and the normal DT APIs refs them from orig flat DT
- */
-void __init copy_devtree(void)
-{
- void *alloc = early_init_dt_alloc_memory_arch(
- be32_to_cpu(initial_boot_params->totalsize), 64);
- if (alloc) {
- memcpy(alloc, initial_boot_params,
- be32_to_cpu(initial_boot_params->totalsize));
- initial_boot_params = alloc;
- }
+ return mdesc;
}
diff --git a/arch/arc/kernel/disasm.c b/arch/arc/kernel/disasm.c
index 2f390289a79..b8a549c4f54 100644
--- a/arch/arc/kernel/disasm.c
+++ b/arch/arc/kernel/disasm.c
@@ -12,8 +12,8 @@
#include <linux/types.h>
#include <linux/kprobes.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <asm/disasm.h>
-#include <asm/uaccess.h>
#if defined(CONFIG_KGDB) || defined(CONFIG_ARC_MISALIGN_ACCESS) || \
defined(CONFIG_KPROBES)
@@ -535,4 +535,4 @@ int __kprobes disasm_next_pc(unsigned long pc, struct pt_regs *regs,
return instr.is_branch;
}
-#endif /* CONFIG_KGDB || CONFIG_MISALIGN_ACCESS || CONFIG_KPROBES */
+#endif /* CONFIG_KGDB || CONFIG_ARC_MISALIGN_ACCESS || CONFIG_KPROBES */
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index ef6800ba2f0..83a046a7cd0 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -141,8 +141,8 @@ VECTOR EV_Extension ; 0x130, Extn Intruction Excp (0x26)
VECTOR reserved ; Reserved Exceptions
.endr
-#include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */
-#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */
+#include <linux/linkage.h> /* {EXTRY,EXIT} */
+#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,SYS...} */
#include <asm/errno.h>
#include <asm/arcregs.h>
#include <asm/irqflags.h>
@@ -156,7 +156,7 @@ ARCFP_DATA int1_saved_reg
int1_saved_reg:
.zero 4
-/* Each Interrupt level needs it's own scratch */
+/* Each Interrupt level needs its own scratch */
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
ARCFP_DATA int2_saved_reg
@@ -184,7 +184,7 @@ reserved: ; processor restart
; ---------------------------------------------
; Level 2 ISR: Can interrupt a Level 1 ISR
; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level2
+ENTRY(handle_interrupt_level2)
; TODO-vineetg for SMP this wont work
; free up r9 as scratchpad
@@ -225,14 +225,14 @@ ARC_ENTRY handle_interrupt_level2
b ret_from_exception
-ARC_EXIT handle_interrupt_level2
+END(handle_interrupt_level2)
#endif
; ---------------------------------------------
; Level 1 ISR
; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level1
+ENTRY(handle_interrupt_level1)
/* free up r9 as scratchpad */
#ifdef CONFIG_SMP
@@ -250,6 +250,14 @@ ARC_ENTRY handle_interrupt_level1
lr r0, [icause1]
and r0, r0, 0x1f
+#ifdef CONFIG_TRACE_IRQFLAGS
+ ; icause1 needs to be read early, before calling tracing, which
+ ; can clobber scratch regs, hence use of stack to stash it
+ push r0
+ TRACE_ASM_IRQ_DISABLE
+ pop r0
+#endif
+
bl.d @arch_do_IRQ
mov r1, sp
@@ -257,7 +265,7 @@ ARC_ENTRY handle_interrupt_level1
sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg
b ret_from_exception
-ARC_EXIT handle_interrupt_level1
+END(handle_interrupt_level1)
;################### Non TLB Exception Handling #############################
@@ -265,63 +273,52 @@ ARC_EXIT handle_interrupt_level1
; Instruction Error Exception Handler
; ---------------------------------------------
-ARC_ENTRY instr_service
-
- EXCPN_PROLOG_FREEUP_REG r9
-
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ENTRY(instr_service)
- lr r0, [ecr]
- lr r1, [efa]
+ EXCEPTION_PROLOGUE
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
bl do_insterror_or_kprobe
b ret_from_exception
-ARC_EXIT instr_service
+END(instr_service)
; ---------------------------------------------
; Memory Error Exception Handler
; ---------------------------------------------
-ARC_ENTRY mem_service
+ENTRY(mem_service)
- EXCPN_PROLOG_FREEUP_REG r9
+ EXCEPTION_PROLOGUE
- lr r9, [erstatus]
+ lr r0, [efa]
+ mov r1, sp
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ FAKE_RET_FROM_EXCPN r9
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
bl do_memory_error
b ret_from_exception
-ARC_EXIT mem_service
+END(mem_service)
; ---------------------------------------------
; Machine Check Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_MachineCheck
+ENTRY(EV_MachineCheck)
- EXCPN_PROLOG_FREEUP_REG r9
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ lr r2, [ecr]
+ lr r0, [efa]
+ mov r1, sp
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lsr r3, r2, 8
+ bmsk r3, r3, 7
+ brne r3, ECR_C_MCHK_DUP_TLB, 1f
- brne r0, 0x200100, 1f
bl do_tlb_overlap_fault
b ret_from_exception
@@ -334,29 +331,23 @@ ARC_ENTRY EV_MachineCheck
j do_machine_check_fault
-ARC_EXIT EV_MachineCheck
+END(EV_MachineCheck)
; ---------------------------------------------
; Protection Violation Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_TLBProtV
-
- EXCPN_PROLOG_FREEUP_REG r9
+ENTRY(EV_TLBProtV)
- ;Which mode (user/kernel) was the system in when Exception occured
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ EXCEPTION_PROLOGUE
;---------(3) Save some more regs-----------------
; vineetg: Mar 6th: Random Seg Fault issue #1
; ecr and efa were not saved in case an Intr sneaks in
; after fake rtie
- ;
- lr r3, [ecr]
- lr r4, [efa]
+
+ lr r2, [ecr]
+ lr r0, [efa] ; Faulting Data address
; --------(4) Return from CPU Exception Mode ---------
; Fake a rtie, but rtie to next label
@@ -365,85 +356,68 @@ ARC_ENTRY EV_TLBProtV
FAKE_RET_FROM_EXCPN r9
+ mov r1, sp
+
;------ (5) Type of Protection Violation? ----------
;
; ProtV Hardware Exception is triggered for Access Faults of 2 types
- ; -Access Violaton (WRITE to READ ONLY Page) - for linux COW
- ; -Unaligned Access (READ/WRITE on odd boundary)
+ ; -Access Violaton : 00_23_(00|01|02|03)_00
+ ; x r w r+w
+ ; -Unaligned Access : 00_23_04_00
;
- cmp r3, 0x230400 ; Misaligned data access ?
- beq 4f
+ bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
;========= (6a) Access Violation Processing ========
- cmp r3, 0x230100
- mov r1, 0x0 ; if LD exception ? write = 0
- mov.ne r1, 0x1 ; else write = 1
-
- mov r2, r4 ; faulting address
- mov r0, sp ; pt_regs
bl do_page_fault
b ret_from_exception
;========== (6b) Non aligned access ============
4:
- mov r0, r3 ; cause code
- mov r1, r4 ; faulting address
- mov r2, sp ; pt_regs
-#ifdef CONFIG_ARC_MISALIGN_ACCESS
SAVE_CALLEE_SAVED_USER
- mov r3, sp ; callee_regs
-#endif
+ mov r2, sp ; callee_regs
bl do_misaligned_access
-#ifdef CONFIG_ARC_MISALIGN_ACCESS
- DISCARD_CALLEE_SAVED_USER
-#endif
+ ; TBD: optimize - do this only if a callee reg was involved
+ ; either a dst of emulated LD/ST or src with address-writeback
+ RESTORE_CALLEE_SAVED_USER
b ret_from_exception
-ARC_EXIT EV_TLBProtV
+END(EV_TLBProtV)
; ---------------------------------------------
; Privilege Violation Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_PrivilegeV
-
- EXCPN_PROLOG_FREEUP_REG r9
+ENTRY(EV_PrivilegeV)
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
-
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
bl do_privilege_fault
b ret_from_exception
-ARC_EXIT EV_PrivilegeV
+END(EV_PrivilegeV)
; ---------------------------------------------
; Extension Instruction Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_Extension
+ENTRY(EV_Extension)
- EXCPN_PROLOG_FREEUP_REG r9
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ lr r0, [efa]
+ mov r1, sp
+
+ FAKE_RET_FROM_EXCPN r9
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
bl do_extension_fault
b ret_from_exception
-ARC_EXIT EV_Extension
+END(EV_Extension)
;######################### System Call Tracing #########################
@@ -452,7 +426,7 @@ tracesys:
; using ERET won't work since next-PC has already committed
lr r12, [efa]
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11
- st r12, [r11, THREAD_FAULT_ADDR]
+ st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address
; PRE Sys Call Ptrace hook
mov r0, sp ; pt_regs needed
@@ -496,13 +470,10 @@ tracesys_exit:
trap_with_param:
; stop_pc info by gdb needs this info
- stw orig_r8_IS_BRKPT, [sp, PT_orig_r8]
-
- mov r0, r12
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
- ; Now that we have read EFA, its safe to do "fake" rtie
+ ; Now that we have read EFA, it is safe to do "fake" rtie
; and get out of CPU exception mode
FAKE_RET_FROM_EXCPN r11
@@ -533,20 +504,13 @@ trap_with_param:
; (2) Break Points
;------------------------------------------------------------------
-ARC_ENTRY EV_Trap
+ENTRY(EV_Trap)
- ; Need at least 1 reg to code the early exception prolog
- EXCPN_PROLOG_FREEUP_REG r9
-
- ;Which mode (user/kernel) was the system in when intr occured
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_TRAP
+ EXCEPTION_PROLOGUE
;------- (4) What caused the Trap --------------
lr r12, [ecr]
- and.f 0, r12, ECR_PARAM_MASK
+ bmsk.f 0, r12, 7
bnz trap_with_param
; ======= (5a) Trap is due to System Call ========
@@ -570,9 +534,9 @@ ARC_ENTRY EV_Trap
jl [r9] ; Entry into Sys Call Handler
; fall through to ret_from_system_call
-ARC_EXIT EV_Trap
+END(EV_Trap)
-ARC_ENTRY ret_from_system_call
+ENTRY(ret_from_system_call)
st r0, [sp, PT_r0] ; sys call return value in pt_regs
@@ -582,16 +546,12 @@ ARC_ENTRY ret_from_system_call
;
; If ret to user mode do we need to handle signals, schedule() et al.
-ARC_ENTRY ret_from_exception
+ENTRY(ret_from_exception)
; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
ld r8, [sp, PT_status32] ; returning to User/Kernel Mode
-#ifdef CONFIG_PREEMPT
bbit0 r8, STATUS_U_BIT, resume_kernel_mode
-#else
- bbit0 r8, STATUS_U_BIT, restore_regs
-#endif
; Before returning to User mode check-for-and-complete any pending work
; such as rescheduling/signal-delivery etc.
@@ -618,6 +578,7 @@ resume_user_mode_begin:
; --- (Slow Path #2) pending signal ---
mov r0, sp ; pt_regs for arg to do_signal()/do_notify_resume()
+ GET_CURR_THR_INFO_FLAGS r9
bbit0 r9, TIF_SIGPENDING, .Lchk_notify_resume
; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs
@@ -651,10 +612,15 @@ resume_user_mode_begin:
b resume_user_mode_begin ; unconditionally back to U mode ret chks
; for single exit point from this block
-#ifdef CONFIG_PREEMPT
-
resume_kernel_mode:
+ ; Disable Interrupts from this point on
+ ; CONFIG_PREEMPT: This is a must for preempt_schedule_irq()
+ ; !CONFIG_PREEMPT: To ensure restore_regs is intr safe
+ IRQ_DISABLE r9
+
+#ifdef CONFIG_PREEMPT
+
; Can't preempt if preemption disabled
GET_CURR_THR_INFO_FROM_SP r10
ld r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -664,8 +630,6 @@ resume_kernel_mode:
ld r9, [r10, THREAD_INFO_FLAGS]
bbit0 r9, TIF_NEED_RESCHED, restore_regs
- IRQ_DISABLE r9
-
; Invoke PREEMPTION
bl preempt_schedule_irq
@@ -678,23 +642,13 @@ resume_kernel_mode:
;
; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
; IRQ shd definitely not happen between now and rtie
+; All 2 entry points to here already disable interrupts
restore_regs :
- ; Disable Interrupts while restoring reg-file back
- ; XXX can this be optimised out
- IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy
-
-#ifdef CONFIG_ARC_CURR_IN_REG
- ; Restore User R25
- ; Earlier this used to be only for returning to user mode
- ; However with 2 levels of IRQ this can also happen even if
- ; in kernel mode
- ld r9, [sp, PT_sp]
- brhs r9, VMALLOC_START, 8f
- RESTORE_USER_R25
-8:
-#endif
+ TRACE_ASM_IRQ_ENABLE
+
+ lr r10, [status32]
; Restore REG File. In case multiple Events outstanding,
; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
@@ -712,28 +666,33 @@ not_exception:
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
+ ; Level 2 interrupt return Path - from hardware standpoint
bbit0 r10, STATUS_A2_BIT, not_level2_interrupt
;------------------------------------------------------------------
- ; if L2 IRQ interrupted a L1 ISR, we'd disbaled preemption earlier
- ; so that sched doesnt move to new task, causing L1 to be delayed
- ; undeterministically. Now that we've achieved that, lets reset
+ ; However the context returning might not have taken L2 intr itself
+ ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
+ ; Special considerations needed for the context which took L2 intr
+
+ ld r9, [sp, PT_event] ; Ensure this is L2 intr context
+ brne r9, event_IRQ2, 149f
+
+ ;------------------------------------------------------------------
+ ; if L2 IRQ interrupted an L1 ISR, we'd disabled preemption earlier
+ ; so that sched doesn't move to new task, causing L1 to be delayed
+ ; undeterministically. Now that we've achieved that, let's reset
; things to what they were, before returning from L2 context
;----------------------------------------------------------------
- ldw r9, [sp, PT_orig_r8] ; get orig_r8 to make sure it is
- brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
-
ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
bbit0 r9, STATUS_A1_BIT, 149f ; L1 not active when L2 IRQ, so normal
- ; A1 is set in status32_l2
; decrement thread_info->preempt_count (re-enable preemption)
GET_CURR_THR_INFO_FROM_SP r10
ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
; paranoid check, given A1 was active when A2 happened, preempt count
- ; must not be 0 beccause we would have incremented it.
+ ; must not be 0 because we would have incremented it.
; If this does happen we simply HALT as it means a BUG !!!
cmp r9, 0
bnz 2f
@@ -769,15 +728,15 @@ not_level1_interrupt:
debug_marker_syscall:
rtie
-ARC_EXIT ret_from_exception
+END(ret_from_exception)
-ARC_ENTRY ret_from_fork
+ENTRY(ret_from_fork)
; when the forked child comes here from the __switch_to function
; r0 has the last task pointer.
; put last task in scheduler queue
bl @schedule_tail
- ; If kernel thread, jump to it's entry-point
+ ; If kernel thread, jump to its entry-point
ld r9, [sp, PT_status32]
brne r9, 0, 1f
@@ -788,36 +747,11 @@ ARC_ENTRY ret_from_fork
; special case of kernel_thread entry point returning back due to
; kernel_execve() - pretend return from syscall to ret to userland
b ret_from_exception
-ARC_EXIT ret_from_fork
+END(ret_from_fork)
;################### Special Sys Call Wrappers ##########################
-; TBD: call do_fork directly from here
-ARC_ENTRY sys_fork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_fork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_fork_wrapper
-
-ARC_ENTRY sys_vfork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_vfork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_vfork_wrapper
-
-ARC_ENTRY sys_clone_wrapper
+ENTRY(sys_clone_wrapper)
SAVE_CALLEE_SAVED_USER
bl @sys_clone
DISCARD_CALLEE_SAVED_USER
@@ -827,7 +761,7 @@ ARC_ENTRY sys_clone_wrapper
bnz tracesys_exit
b ret_from_system_call
-ARC_EXIT sys_clone_wrapper
+END(sys_clone_wrapper)
#ifdef CONFIG_ARC_DW2_UNWIND
; Workaround for bug 94179 (STAR ):
diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S
index 006dec3fc35..4d2481bd8b9 100644
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -12,10 +12,42 @@
* to skip certain things during boot on simulator
*/
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/entry.h>
-#include <linux/linkage.h>
#include <asm/arcregs.h>
+#include <asm/cache.h>
+
+.macro CPU_EARLY_SETUP
+
+ ; Setting up Vectror Table (in case exception happens in early boot
+ sr @_int_vec_base_lds, [AUX_INTR_VEC_BASE]
+
+ ; Disable I-cache/D-cache if kernel so configured
+ lr r5, [ARC_REG_IC_BCR]
+ breq r5, 0, 1f ; I$ doesn't exist
+ lr r5, [ARC_REG_IC_CTRL]
+#ifdef CONFIG_ARC_HAS_ICACHE
+ bclr r5, r5, 0 ; 0 - Enable, 1 is Disable
+#else
+ bset r5, r5, 0 ; I$ exists, but is not used
+#endif
+ sr r5, [ARC_REG_IC_CTRL]
+
+1:
+ lr r5, [ARC_REG_DC_BCR]
+ breq r5, 0, 1f ; D$ doesn't exist
+ lr r5, [ARC_REG_DC_CTRL]
+ bclr r5, r5, 6 ; Invalidate (discard w/o wback)
+#ifdef CONFIG_ARC_HAS_DCACHE
+ bclr r5, r5, 0 ; Enable (+Inv)
+#else
+ bset r5, r5, 0 ; Disable (+Inv)
+#endif
+ sr r5, [ARC_REG_DC_CTRL]
+
+1:
+.endm
.cpu A7
@@ -24,45 +56,40 @@
.globl stext
stext:
;-------------------------------------------------------------------
- ; Don't clobber r0-r4 yet. It might have bootloader provided info
+ ; Don't clobber r0-r2 yet. It might have bootloader provided info
;-------------------------------------------------------------------
+ CPU_EARLY_SETUP
+
#ifdef CONFIG_SMP
- ; Only Boot (Master) proceeds. Others wait in platform dependent way
+ ; Ensure Boot (Master) proceeds. Others wait in platform dependent way
; IDENTITY Reg [ 3 2 1 0 ]
; (cpu-id) ^^^ => Zero for UP ARC700
; => #Core-ID if SMP (Master 0)
+ ; Note that non-boot CPUs might not land here if halt-on-reset and
+ ; instead breath life from @first_lines_of_secondary, but we still
+ ; need to make sure only boot cpu takes this path.
GET_CPU_ID r5
cmp r5, 0
- jnz arc_platform_smp_wait_to_boot
+ mov.ne r0, r5
+ jne arc_platform_smp_wait_to_boot
#endif
; Clear BSS before updating any globals
; XXX: use ZOL here
mov r5, __bss_start
- mov r6, __bss_stop
+ sub r6, __bss_stop, r5
+ lsr.f lp_count, r6, 2
+ lpnz 1f
+ st.ab 0, [r5, 4]
1:
- st.ab 0, [r5,4]
- brlt r5, r6, 1b
-
-#ifdef CONFIG_CMDLINE_UBOOT
- ; support for bootloader provided cmdline
- ; If cmdline passed by u-boot, then
- ; r0 = 1 (because ATAGS parsing, now retired, used to use 0)
- ; r1 = magic number (board identity)
- ; r2 = addr of cmdline string (somewhere in memory/flash)
- brne r0, 1, .Lother_bootup_chores ; u-boot didn't pass cmdline
- breq r2, 0, .Lother_bootup_chores ; or cmdline is NULL
-
- mov r5, @command_line
-1:
- ldb.ab r6, [r2, 1]
- breq r6, 0, .Lother_bootup_chores
- b.d 1b
- stb.ab r6, [r5, 1]
-#endif
-
-.Lother_bootup_chores:
+ ; Uboot - kernel ABI
+ ; r0 = [0] No uboot interaction, [1] cmdline in r2, [2] DTB in r2
+ ; r1 = magic number (board identity, unused as of now
+ ; r2 = pointer to uboot provided cmdline or external DTB in mem
+ ; These are handled later in setup_arch()
+ st r0, [@uboot_tag]
+ st r2, [@uboot_arg]
; Identify if running on ISS vs Silicon
; IDENTITY Reg [ 3 2 1 0 ]
@@ -90,12 +117,14 @@ stext:
;----------------------------------------------------------------
; First lines of code run by secondary before jumping to 'C'
;----------------------------------------------------------------
- .section .init.text, "ax",@progbits
+ .section .text, "ax",@progbits
.type first_lines_of_secondary, @function
.globl first_lines_of_secondary
first_lines_of_secondary:
+ CPU_EARLY_SETUP
+
; setup per-cpu idle task as "current" on this CPU
ld r0, [@secondary_idle_tsk]
SET_CURR_TASK_ON_CPU r0, r1
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index 551c10dff48..7d653c0d077 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include "../../drivers/irqchip/irqchip.h"
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/mach_desc.h>
@@ -22,34 +24,29 @@
* -Needed for each CPU (hence not foldable into init_IRQ)
*
* what it does ?
- * -setup Vector Table Base Reg - in case Linux not linked at 0x8000_0000
* -Disable all IRQs (on CPU side)
* -Optionally, setup the High priority Interrupts as Level 2 IRQs
*/
-void __init arc_init_IRQ(void)
+void arc_init_IRQ(void)
{
int level_mask = 0;
- write_aux_reg(AUX_INTR_VEC_BASE, _int_vec_base_lds);
-
/* Disable all IRQs: enable them as devices request */
write_aux_reg(AUX_IENABLE, 0);
/* setup any high priority Interrupts (Level2 in ARCompact jargon) */
-#ifdef CONFIG_ARC_IRQ3_LV2
- level_mask |= (1 << 3);
-#endif
-#ifdef CONFIG_ARC_IRQ5_LV2
- level_mask |= (1 << 5);
-#endif
-#ifdef CONFIG_ARC_IRQ6_LV2
- level_mask |= (1 << 6);
-#endif
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3;
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5;
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ6_LV2) << 6;
+
+ /*
+ * Write to register, even if no LV2 IRQs configured to reset it
+ * in case bootloader had mucked with it
+ */
+ write_aux_reg(AUX_IRQ_LEV, level_mask);
- if (level_mask) {
+ if (level_mask)
pr_info("Level-2 interrupts bitset %x\n", level_mask);
- write_aux_reg(AUX_IRQ_LEV, level_mask);
- }
}
/*
@@ -97,15 +94,13 @@ static const struct irq_domain_ops arc_intc_domain_ops = {
static struct irq_domain *root_domain;
-void __init init_onchip_IRQ(void)
+static int __init
+init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
{
- struct device_node *intc = NULL;
+ if (parent)
+ panic("DeviceTree incore intc not a root irq controller\n");
- intc = of_find_compatible_node(NULL, NULL, "snps,arc700-intc");
- if(!intc)
- panic("DeviceTree Missing incore intc\n");
-
- root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
+ root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0,
&arc_intc_domain_ops, NULL);
if (!root_domain)
@@ -113,8 +108,12 @@ void __init init_onchip_IRQ(void)
/* with this we don't need to export root_domain */
irq_set_default_host(root_domain);
+
+ return 0;
}
+IRQCHIP_DECLARE(arc_intc, "snps,arc700-intc", init_onchip_IRQ);
+
/*
* Late Interrupt system init called from start_kernel for Boot CPU only
*
@@ -123,12 +122,13 @@ void __init init_onchip_IRQ(void)
*/
void __init init_IRQ(void)
{
- init_onchip_IRQ();
-
/* Any external intc can be setup here */
if (machine_desc->init_irq)
machine_desc->init_irq();
+ /* process the entire interrupt tree in one go */
+ irqchip_init();
+
#ifdef CONFIG_SMP
/* Master CPU can initialize it's side of IPI */
if (machine_desc->init_smp)
@@ -150,24 +150,6 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}
-int __init get_hw_config_num_irq(void)
-{
- uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
-
- switch (val & 0x03) {
- case 0:
- return 16;
- case 1:
- return 32;
- case 2:
- return 8;
- default:
- return 0;
- }
-
- return 0;
-}
-
/*
* arch_local_irq_enable - Enable interrupts.
*
diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c
index 2888ba5be47..a2ff5c5d145 100644
--- a/arch/arc/kernel/kgdb.c
+++ b/arch/arc/kernel/kgdb.c
@@ -9,6 +9,7 @@
*/
#include <linux/kgdb.h>
+#include <linux/sched.h>
#include <asm/disasm.h>
#include <asm/cacheflush.h>
@@ -168,7 +169,7 @@ int kgdb_arch_init(void)
return 0;
}
-void kgdb_trap(struct pt_regs *regs, int param)
+void kgdb_trap(struct pt_regs *regs)
{
/* trap_s 3 is used for breakpoints that overwrite existing
* instructions, while trap_s 4 is used for compiled breakpoints.
@@ -180,7 +181,7 @@ void kgdb_trap(struct pt_regs *regs, int param)
* with trap_s 4 (compiled) breakpoints, continuation needs to
* start after the breakpoint.
*/
- if (param == 3)
+ if (regs->ecr_param == 3)
instruction_pointer(regs) -= BREAK_INSTR_SIZE;
kgdb_handle_exception(1, SIGTRAP, 0, regs);
@@ -195,6 +196,18 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
instruction_pointer(regs) = ip;
}
+static void kgdb_call_nmi_hook(void *ignored)
+{
+ kgdb_nmicallback(raw_smp_processor_id(), NULL);
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ local_irq_enable();
+ smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+ local_irq_disable();
+}
+
struct kgdb_arch arch_kgdb_ops = {
/* breakpoint instruction: TRAP_S 0x3 */
#ifdef CONFIG_CPU_BIG_ENDIAN
diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c
index 3bfeacb674d..42b05046fad 100644
--- a/arch/arc/kernel/kprobes.c
+++ b/arch/arc/kernel/kprobes.c
@@ -10,7 +10,6 @@
#include <linux/kprobes.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/kprobes.h>
#include <linux/kdebug.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
@@ -88,13 +87,13 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
- __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+ __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
kcb->kprobe_status = kcb->prev_kprobe.status;
}
static inline void __kprobes set_current_kprobe(struct kprobe *p)
{
- __get_cpu_var(current_kprobe) = p;
+ __this_cpu_write(current_kprobe, p);
}
static void __kprobes resume_execution(struct kprobe *p, unsigned long addr,
@@ -238,7 +237,7 @@ int __kprobes arc_kprobe_handler(unsigned long addr, struct pt_regs *regs)
return 1;
} else if (kprobe_running()) {
- p = __get_cpu_var(current_kprobe);
+ p = __this_cpu_read(current_kprobe);
if (p->break_handler && p->break_handler(p, regs)) {
setup_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
@@ -328,7 +327,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr)
*/
/* We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
+ * we can also use npre/npostfault count for accounting
* these specific fault cases.
*/
kprobes_inc_nmissed_count(cur);
@@ -518,8 +517,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
return 0;
}
-void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
{
- notify_die(DIE_TRAP, "kprobe_trap", regs, address, cause, SIGTRAP);
+ notify_die(DIE_TRAP, "kprobe_trap", regs, address, 0, SIGTRAP);
}
diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c
index cdd359352c0..376e0462296 100644
--- a/arch/arc/kernel/module.c
+++ b/arch/arc/kernel/module.c
@@ -47,7 +47,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
}
}
#endif
- return 0;
+ return 0;
}
void module_arch_cleanup(struct module *mod)
@@ -141,5 +141,5 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
mod->arch.unw_info = unw;
}
#endif
- return 0;
+ return 0;
}
diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c
new file mode 100644
index 00000000000..63177e4cb66
--- /dev/null
+++ b/arch/arc/kernel/perf_event.c
@@ -0,0 +1,326 @@
+/*
+ * Linux performance counter support for ARC700 series
+ *
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This code is inspired by the perf support of various other architectures.
+ *
+ * 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/errno.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <asm/arcregs.h>
+
+struct arc_pmu {
+ struct pmu pmu;
+ int counter_size; /* in bits */
+ int n_counters;
+ unsigned long used_mask[BITS_TO_LONGS(ARC_PMU_MAX_HWEVENTS)];
+ int ev_hw_idx[PERF_COUNT_ARC_HW_MAX];
+};
+
+/* read counter #idx; note that counter# != event# on ARC! */
+static uint64_t arc_pmu_read_counter(int idx)
+{
+ uint32_t tmp;
+ uint64_t result;
+
+ /*
+ * ARC supports making 'snapshots' of the counters, so we don't
+ * need to care about counters wrapping to 0 underneath our feet
+ */
+ write_aux_reg(ARC_REG_PCT_INDEX, idx);
+ tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
+ write_aux_reg(ARC_REG_PCT_CONTROL, tmp | ARC_REG_PCT_CONTROL_SN);
+ result = (uint64_t) (read_aux_reg(ARC_REG_PCT_SNAPH)) << 32;
+ result |= read_aux_reg(ARC_REG_PCT_SNAPL);
+
+ return result;
+}
+
+static void arc_perf_event_update(struct perf_event *event,
+ struct hw_perf_event *hwc, int idx)
+{
+ struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu);
+ uint64_t prev_raw_count, new_raw_count;
+ int64_t delta;
+
+ do {
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = arc_pmu_read_counter(idx);
+ } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count);
+
+ delta = (new_raw_count - prev_raw_count) &
+ ((1ULL << arc_pmu->counter_size) - 1ULL);
+
+ local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
+}
+
+static void arc_pmu_read(struct perf_event *event)
+{
+ arc_perf_event_update(event, &event->hw, event->hw.idx);
+}
+
+static int arc_pmu_cache_event(u64 config)
+{
+ unsigned int cache_type, cache_op, cache_result;
+ int ret;
+
+ cache_type = (config >> 0) & 0xff;
+ cache_op = (config >> 8) & 0xff;
+ cache_result = (config >> 16) & 0xff;
+ if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+ return -EINVAL;
+ if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+ return -EINVAL;
+ if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+ return -EINVAL;
+
+ ret = arc_pmu_cache_map[cache_type][cache_op][cache_result];
+
+ if (ret == CACHE_OP_UNSUPPORTED)
+ return -ENOENT;
+
+ return ret;
+}
+
+/* initializes hw_perf_event structure if event is supported */
+static int arc_pmu_event_init(struct perf_event *event)
+{
+ struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int ret;
+
+ /* ARC 700 PMU does not support sampling events */
+ if (is_sampling_event(event))
+ return -ENOENT;
+
+ switch (event->attr.type) {
+ case PERF_TYPE_HARDWARE:
+ if (event->attr.config >= PERF_COUNT_HW_MAX)
+ return -ENOENT;
+ if (arc_pmu->ev_hw_idx[event->attr.config] < 0)
+ return -ENOENT;
+ hwc->config = arc_pmu->ev_hw_idx[event->attr.config];
+ pr_debug("initializing event %d with cfg %d\n",
+ (int) event->attr.config, (int) hwc->config);
+ return 0;
+ case PERF_TYPE_HW_CACHE:
+ ret = arc_pmu_cache_event(event->attr.config);
+ if (ret < 0)
+ return ret;
+ hwc->config = arc_pmu->ev_hw_idx[ret];
+ return 0;
+ default:
+ return -ENOENT;
+ }
+}
+
+/* starts all counters */
+static void arc_pmu_enable(struct pmu *pmu)
+{
+ uint32_t tmp;
+ tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
+ write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x1);
+}
+
+/* stops all counters */
+static void arc_pmu_disable(struct pmu *pmu)
+{
+ uint32_t tmp;
+ tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
+ write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x0);
+}
+
+/*
+ * Assigns hardware counter to hardware condition.
+ * Note that there is no separate start/stop mechanism;
+ * stopping is achieved by assigning the 'never' condition
+ */
+static void arc_pmu_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (WARN_ON_ONCE(idx == -1))
+ return;
+
+ if (flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+ event->hw.state = 0;
+
+ /* enable ARC pmu here */
+ write_aux_reg(ARC_REG_PCT_INDEX, idx);
+ write_aux_reg(ARC_REG_PCT_CONFIG, hwc->config);
+}
+
+static void arc_pmu_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (!(event->hw.state & PERF_HES_STOPPED)) {
+ /* stop ARC pmu here */
+ write_aux_reg(ARC_REG_PCT_INDEX, idx);
+
+ /* condition code #0 is always "never" */
+ write_aux_reg(ARC_REG_PCT_CONFIG, 0);
+
+ event->hw.state |= PERF_HES_STOPPED;
+ }
+
+ if ((flags & PERF_EF_UPDATE) &&
+ !(event->hw.state & PERF_HES_UPTODATE)) {
+ arc_perf_event_update(event, &event->hw, idx);
+ event->hw.state |= PERF_HES_UPTODATE;
+ }
+}
+
+static void arc_pmu_del(struct perf_event *event, int flags)
+{
+ struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu);
+
+ arc_pmu_stop(event, PERF_EF_UPDATE);
+ __clear_bit(event->hw.idx, arc_pmu->used_mask);
+
+ perf_event_update_userpage(event);
+}
+
+/* allocate hardware counter and optionally start counting */
+static int arc_pmu_add(struct perf_event *event, int flags)
+{
+ struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (__test_and_set_bit(idx, arc_pmu->used_mask)) {
+ idx = find_first_zero_bit(arc_pmu->used_mask,
+ arc_pmu->n_counters);
+ if (idx == arc_pmu->n_counters)
+ return -EAGAIN;
+
+ __set_bit(idx, arc_pmu->used_mask);
+ hwc->idx = idx;
+ }
+
+ write_aux_reg(ARC_REG_PCT_INDEX, idx);
+ write_aux_reg(ARC_REG_PCT_CONFIG, 0);
+ write_aux_reg(ARC_REG_PCT_COUNTL, 0);
+ write_aux_reg(ARC_REG_PCT_COUNTH, 0);
+ local64_set(&hwc->prev_count, 0);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ arc_pmu_start(event, PERF_EF_RELOAD);
+
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+static int arc_pmu_device_probe(struct platform_device *pdev)
+{
+ struct arc_pmu *arc_pmu;
+ struct arc_reg_pct_build pct_bcr;
+ struct arc_reg_cc_build cc_bcr;
+ int i, j, ret;
+
+ union cc_name {
+ struct {
+ uint32_t word0, word1;
+ char sentinel;
+ } indiv;
+ char str[9];
+ } cc_name;
+
+
+ READ_BCR(ARC_REG_PCT_BUILD, pct_bcr);
+ if (!pct_bcr.v) {
+ pr_err("This core does not have performance counters!\n");
+ return -ENODEV;
+ }
+
+ arc_pmu = devm_kzalloc(&pdev->dev, sizeof(struct arc_pmu),
+ GFP_KERNEL);
+ if (!arc_pmu)
+ return -ENOMEM;
+
+ arc_pmu->n_counters = pct_bcr.c;
+ BUG_ON(arc_pmu->n_counters > ARC_PMU_MAX_HWEVENTS);
+
+ arc_pmu->counter_size = 32 + (pct_bcr.s << 4);
+ pr_info("ARC PMU found with %d counters of size %d bits\n",
+ arc_pmu->n_counters, arc_pmu->counter_size);
+
+ READ_BCR(ARC_REG_CC_BUILD, cc_bcr);
+
+ if (!cc_bcr.v)
+ pr_err("Strange! Performance counters exist, but no countable conditions?\n");
+
+ pr_info("ARC PMU has %d countable conditions\n", cc_bcr.c);
+
+ cc_name.str[8] = 0;
+ for (i = 0; i < PERF_COUNT_HW_MAX; i++)
+ arc_pmu->ev_hw_idx[i] = -1;
+
+ for (j = 0; j < cc_bcr.c; j++) {
+ write_aux_reg(ARC_REG_CC_INDEX, j);
+ cc_name.indiv.word0 = read_aux_reg(ARC_REG_CC_NAME0);
+ cc_name.indiv.word1 = read_aux_reg(ARC_REG_CC_NAME1);
+ for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) {
+ if (arc_pmu_ev_hw_map[i] &&
+ !strcmp(arc_pmu_ev_hw_map[i], cc_name.str) &&
+ strlen(arc_pmu_ev_hw_map[i])) {
+ pr_debug("mapping %d to idx %d with name %s\n",
+ i, j, cc_name.str);
+ arc_pmu->ev_hw_idx[i] = j;
+ }
+ }
+ }
+
+ arc_pmu->pmu = (struct pmu) {
+ .pmu_enable = arc_pmu_enable,
+ .pmu_disable = arc_pmu_disable,
+ .event_init = arc_pmu_event_init,
+ .add = arc_pmu_add,
+ .del = arc_pmu_del,
+ .start = arc_pmu_start,
+ .stop = arc_pmu_stop,
+ .read = arc_pmu_read,
+ };
+
+ ret = perf_pmu_register(&arc_pmu->pmu, pdev->name, PERF_TYPE_RAW);
+
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id arc_pmu_match[] = {
+ { .compatible = "snps,arc700-pmu" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, arc_pmu_match);
+#endif
+
+static struct platform_driver arc_pmu_driver = {
+ .driver = {
+ .name = "arc700-pmu",
+ .of_match_table = of_match_ptr(arc_pmu_match),
+ },
+ .probe = arc_pmu_device_probe,
+};
+
+module_platform_driver(arc_pmu_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mischa Jonker <mjonker@synopsys.com>");
+MODULE_DESCRIPTION("ARC PMU driver");
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index 0a7531d9929..fdd89715d2d 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -41,37 +41,12 @@ SYSCALL_DEFINE0(arc_gettls)
return task_thread_info(current)->thr_ptr;
}
-static inline void arch_idle(void)
+void arch_cpu_idle(void)
{
/* sleep, but enable all interrupts before committing */
__asm__("sleep 0x3");
}
-void cpu_idle(void)
-{
- /* Since we SLEEP in idle loop, TIF_POLLING_NRFLAG can't be set */
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
-doze:
- local_irq_disable();
- if (!need_resched()) {
- arch_idle();
- goto doze;
- } else {
- local_irq_enable();
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
- schedule_preempt_disabled();
- }
-}
-
asmlinkage void ret_from_fork(void);
/* Layout of Child kernel mode stack as setup at the end of this function is
@@ -80,10 +55,8 @@ asmlinkage void ret_from_fork(void);
* | ... |
* | unused |
* | |
- * ------------------ <==== top of Stack (thread.ksp)
- * | UNUSED 1 word|
* ------------------
- * | r25 |
+ * | r25 | <==== top of Stack (thread.ksp)
* ~ ~
* | --to-- | (CALLEE Regs of user mode)
* | r13 |
@@ -101,7 +74,10 @@ asmlinkage void ret_from_fork(void);
* | --to-- | (scratch Regs of user mode)
* | r0 |
* ------------------
- * | UNUSED 1 word|
+ * | SP |
+ * | orig_r0 |
+ * | event/ECR |
+ * | user_r25 |
* ------------------ <===== END of PAGE
*/
int copy_thread(unsigned long clone_flags,
@@ -175,6 +151,29 @@ int copy_thread(unsigned long clone_flags,
}
/*
+ * Do necessary setup to start up a new user task
+ */
+void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
+{
+ set_fs(USER_DS); /* user space */
+
+ regs->sp = usp;
+ regs->ret = pc;
+
+ /*
+ * [U]ser Mode bit set
+ * [L] ZOL loop inhibited to begin with - cleared by a LP insn
+ * Interrupts enabled
+ */
+ regs->status32 = STATUS_U_MASK | STATUS_L_MASK |
+ STATUS_E1_MASK | STATUS_E2_MASK;
+
+ /* bogus seed values for debugging */
+ regs->lp_start = 0x10;
+ regs->lp_end = 0x80;
+}
+
+/*
* Some archs flush debug and FPU info here
*/
void flush_thread(void)
diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c
index c6a81c58d0f..13b3ffb27a3 100644
--- a/arch/arc/kernel/ptrace.c
+++ b/arch/arc/kernel/ptrace.c
@@ -40,7 +40,15 @@ static int genregs_get(struct task_struct *target,
offsetof(struct user_regs_struct, LOC), \
offsetof(struct user_regs_struct, LOC) + 4);
+#define REG_O_ZERO(LOC) \
+ if (!ret) \
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
+ offsetof(struct user_regs_struct, LOC), \
+ offsetof(struct user_regs_struct, LOC) + 4);
+
+ REG_O_ZERO(pad);
REG_O_CHUNK(scratch, callee, ptregs);
+ REG_O_ZERO(pad2);
REG_O_CHUNK(callee, efa, cregs);
REG_O_CHUNK(efa, stop_pc, &target->thread.fault_address);
@@ -88,11 +96,13 @@ static int genregs_set(struct task_struct *target,
offsetof(struct user_regs_struct, LOC), \
offsetof(struct user_regs_struct, LOC) + 4);
- /* TBD: disallow updates to STATUS32, orig_r8 etc*/
- REG_IN_CHUNK(scratch, callee, ptregs); /* pt_regs[bta..orig_r8] */
+ REG_IGNORE_ONE(pad);
+ /* TBD: disallow updates to STATUS32 etc*/
+ REG_IN_CHUNK(scratch, pad2, ptregs); /* pt_regs[bta..sp] */
+ REG_IGNORE_ONE(pad2);
REG_IN_CHUNK(callee, efa, cregs); /* callee_regs[r25..r13] */
REG_IGNORE_ONE(efa); /* efa update invalid */
- REG_IN_ONE(stop_pc, &ptregs->ret); /* stop_pc: PC update */
+ REG_IGNORE_ONE(stop_pc); /* PC updated via @ret */
return ret;
}
@@ -136,6 +146,10 @@ long arch_ptrace(struct task_struct *child, long request,
pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data);
switch (request) {
+ case PTRACE_GET_THREAD_AREA:
+ ret = put_user(task_thread_info(child)->thr_ptr,
+ (unsigned long __user *)data);
+ break;
default:
ret = ptrace_request(child, request, addr, data);
break;
diff --git a/arch/arc/kernel/reset.c b/arch/arc/kernel/reset.c
index e227a2b1c94..2768fa1e39b 100644
--- a/arch/arc/kernel/reset.c
+++ b/arch/arc/kernel/reset.c
@@ -31,3 +31,4 @@ void machine_power_off(void)
}
void (*pm_power_off) (void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index dc0f968dae0..119dddb752b 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -14,15 +14,13 @@
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/of_fdt.h>
+#include <linux/cache.h>
#include <asm/sections.h>
#include <asm/arcregs.h>
#include <asm/tlb.h>
-#include <asm/cache.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/irq.h>
-#include <asm/arcregs.h>
-#include <asm/prom.h>
#include <asm/unwind.h>
#include <asm/clk.h>
#include <asm/mach_desc.h>
@@ -31,15 +29,17 @@
int running_on_hw = 1; /* vs. on ISS */
-char __initdata command_line[COMMAND_LINE_SIZE];
-struct machine_desc *machine_desc __initdata;
+/* Part of U-boot ABI: see head.S */
+int __initdata uboot_tag;
+char __initdata *uboot_arg;
+
+const struct machine_desc *machine_desc;
struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
-
-void __init read_arc_build_cfg_regs(void)
+static void read_arc_build_cfg_regs(void)
{
struct bcr_perip uncached_space;
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -48,10 +48,7 @@ void __init read_arc_build_cfg_regs(void)
READ_BCR(AUX_IDENTITY, cpu->core);
cpu->timers = read_aux_reg(ARC_REG_TIMERS_BCR);
-
cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
- if (cpu->vec_base == 0)
- cpu->vec_base = (unsigned int)_int_vec_base_lds;
READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
cpu->uncached_base = uncached_space.start << 24;
@@ -110,7 +107,7 @@ static const struct cpuinfo_data arc_cpu_tbl[] = {
{ {0x00, NULL } }
};
-char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
+static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
{
int n = 0;
struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
@@ -175,7 +172,7 @@ static const struct id_to_str mac_mul_nm[] = {
{0x6, "Dual 16x16 and 32x16"}
};
-char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
+static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
{
int n = 0;
struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
@@ -183,7 +180,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
FIX_PTR(cpu);
#define IS_AVAIL1(var, str) ((var) ? str : "")
#define IS_AVAIL2(var, str) ((var == 0x2) ? str : "")
-#define IS_USED(var) ((var) ? "(in-use)" : "(not used)")
+#define IS_USED(cfg) (IS_ENABLED(cfg) ? "(in-use)" : "(not used)")
n += scnprintf(buf + n, len - n,
"Extn [700-Base]\t: %s %s %s %s %s %s\n",
@@ -203,9 +200,9 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
if (cpu->core.family == 0x34) {
n += scnprintf(buf + n, len - n,
"Extn [700-4.10]\t: LLOCK/SCOND %s, SWAPE %s, RTSC %s\n",
- IS_USED(__CONFIG_ARC_HAS_LLSC_VAL),
- IS_USED(__CONFIG_ARC_HAS_SWAPE_VAL),
- IS_USED(__CONFIG_ARC_HAS_RTSC_VAL));
+ IS_USED(CONFIG_ARC_HAS_LLSC),
+ IS_USED(CONFIG_ARC_HAS_SWAPE),
+ IS_USED(CONFIG_ARC_HAS_RTSC));
}
n += scnprintf(buf + n, len - n, "Extn [CCM]\t: %s",
@@ -232,15 +229,13 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
n += scnprintf(buf + n, len - n, "\n");
-#ifdef _ASM_GENERIC_UNISTD_H
n += scnprintf(buf + n, len - n,
- "OS ABI [v2]\t: asm-generic/{unistd,stat,fcntl}\n");
-#endif
+ "OS ABI [v3]\t: no-legacy-syscalls\n");
return buf;
}
-void __init arc_chk_ccms(void)
+static void arc_chk_ccms(void)
{
#if defined(CONFIG_ARC_HAS_DCCM) || defined(CONFIG_ARC_HAS_ICCM)
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -275,7 +270,7 @@ void __init arc_chk_ccms(void)
* hardware has dedicated regs which need to be saved/restored on ctx-sw
* (Single Precision uses core regs), thus kernel is kind of oblivious to it
*/
-void __init arc_chk_fpu(void)
+static void arc_chk_fpu(void)
{
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -296,7 +291,7 @@ void __init arc_chk_fpu(void)
* such as only for boot CPU etc
*/
-void __init setup_processor(void)
+void setup_processor(void)
{
char str[512];
int cpu_id = smp_processor_id();
@@ -319,25 +314,43 @@ void __init setup_processor(void)
arc_chk_fpu();
}
+static inline int is_kernel(unsigned long addr)
+{
+ if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
+ return 1;
+ return 0;
+}
+
void __init setup_arch(char **cmdline_p)
{
-#ifdef CONFIG_CMDLINE_UBOOT
- /* Make sure that a whitespace is inserted before */
- strlcat(command_line, " ", sizeof(command_line));
-#endif
- /*
- * Append .config cmdline to base command line, which might already
- * contain u-boot "bootargs" (handled by head.S, if so configured)
- */
- strlcat(command_line, CONFIG_CMDLINE, sizeof(command_line));
+ /* make sure that uboot passed pointer to cmdline/dtb is valid */
+ if (uboot_tag && is_kernel((unsigned long)uboot_arg))
+ panic("Invalid uboot arg\n");
+
+ /* See if u-boot passed an external Device Tree blob */
+ machine_desc = setup_machine_fdt(uboot_arg); /* uboot_tag == 2 */
+ if (!machine_desc) {
+ /* No, so try the embedded one */
+ machine_desc = setup_machine_fdt(__dtb_start);
+ if (!machine_desc)
+ panic("Embedded DT invalid\n");
+
+ /*
+ * If we are here, it is established that @uboot_arg didn't
+ * point to DT blob. Instead if u-boot says it is cmdline,
+ * Appent to embedded DT cmdline.
+ * setup_machine_fdt() would have populated @boot_command_line
+ */
+ if (uboot_tag == 1) {
+ /* Ensure a whitespace between the 2 cmdlines */
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, uboot_arg,
+ COMMAND_LINE_SIZE);
+ }
+ }
/* Save unparsed command line copy for /proc/cmdline */
- strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
- *cmdline_p = command_line;
-
- machine_desc = setup_machine_fdt(__dtb_start);
- if (!machine_desc)
- panic("Embedded DT invalid\n");
+ *cmdline_p = boot_command_line;
/* To force early parsing of things like mem=xxx */
parse_early_param();
@@ -355,16 +368,13 @@ void __init setup_arch(char **cmdline_p)
setup_arch_memory();
/* copy flat DT out of .init and then unflatten it */
- copy_devtree();
- unflatten_device_tree();
+ unflatten_and_copy_device_tree();
/* Can be issue if someone passes cmd line arg "ro"
* But that is unlikely so keeping it as it is
*/
root_mountflags &= ~MS_RDONLY;
- console_verbose();
-
#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c
index ee6ef2f60a2..7e95e1a8651 100644
--- a/arch/arc/kernel/signal.c
+++ b/arch/arc/kernel/signal.c
@@ -101,7 +101,6 @@ SYSCALL_DEFINE0(rt_sigreturn)
{
struct rt_sigframe __user *sf;
unsigned int magic;
- int err;
struct pt_regs *regs = current_pt_regs();
/* Always make any pending restarted system calls return -EINTR */
@@ -119,15 +118,16 @@ SYSCALL_DEFINE0(rt_sigreturn)
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
goto badframe;
- err = restore_usr_regs(regs, sf);
- err |= __get_user(magic, &sf->sigret_magic);
- if (err)
+ if (__get_user(magic, &sf->sigret_magic))
goto badframe;
if (unlikely(is_do_ss_needed(magic)))
if (restore_altstack(&sf->uc.uc_stack))
goto badframe;
+ if (restore_usr_regs(regs, sf))
+ goto badframe;
+
/* Don't restart from sigreturn */
syscall_wont_restart(regs);
@@ -191,6 +191,15 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
return 1;
/*
+ * w/o SA_SIGINFO, struct ucontext is partially populated (only
+ * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
+ * during signal handler execution. This works for SA_SIGINFO as well
+ * although the semantics are now overloaded (the same reg state can be
+ * inspected by userland: but are they allowed to fiddle with it ?
+ */
+ err |= stash_usr_regs(sf, regs, set);
+
+ /*
* SA_SIGINFO requires 3 args to signal handler:
* #1: sig-no (common to any handler)
* #2: struct siginfo
@@ -213,14 +222,6 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
magic = MAGIC_SIGALTSTK;
}
- /*
- * w/o SA_SIGINFO, struct ucontext is partially populated (only
- * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
- * during signal handler execution. This works for SA_SIGINFO as well
- * although the semantics are now overloaded (the same reg state can be
- * inspected by userland: but are they allowed to fiddle with it ?
- */
- err |= stash_usr_regs(sf, regs, set);
err |= __put_user(magic, &sf->sigret_magic);
if (err)
return err;
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 3af3e06dcf0..c802bb50060 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -95,7 +95,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
* If it turns out to be elaborate, it's better to code it in assembly
*
*/
-void __attribute__((weak)) arc_platform_smp_wait_to_boot(int cpu)
+void __weak arc_platform_smp_wait_to_boot(int cpu)
{
/*
* As a hack for debugging - since debugger will single-step over the
@@ -117,7 +117,7 @@ const char *arc_platform_smp_cpuinfo(void)
* Called from asm stub in head.S
* "current"/R25 already setup by low level boot code
*/
-void __cpuinit start_kernel_secondary(void)
+void start_kernel_secondary(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
@@ -128,6 +128,7 @@ void __cpuinit start_kernel_secondary(void)
atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count);
current->active_mm = mm;
+ cpumask_set_cpu(cpu, mm_cpumask(mm));
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
@@ -137,11 +138,11 @@ void __cpuinit start_kernel_secondary(void)
if (machine_desc->init_smp)
machine_desc->init_smp(smp_processor_id());
- arc_local_timer_setup(cpu);
+ arc_local_timer_setup();
local_irq_enable();
preempt_disable();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/*
@@ -154,7 +155,7 @@ void __cpuinit start_kernel_secondary(void)
*
* Essential requirements being where to run from (PC) and stack (SP)
*/
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
{
unsigned long wait_till;
@@ -196,52 +197,65 @@ int __init setup_profiling_timer(unsigned int multiplier)
/* Inter Processor Interrupt Handling */
/*****************************************************************************/
-/*
- * structures for inter-processor calls
- * A Collection of single bit ipi messages
- *
- */
-
-/*
- * TODO_rajesh investigate tlb message types.
- * IPI Timer not needed because each ARC has an individual Interrupting Timer
- */
enum ipi_msg_type {
- IPI_NOP = 0,
+ IPI_EMPTY = 0,
IPI_RESCHEDULE = 1,
IPI_CALL_FUNC,
- IPI_CALL_FUNC_SINGLE,
- IPI_CPU_STOP
+ IPI_CPU_STOP,
};
-struct ipi_data {
- unsigned long bits;
-};
+/*
+ * In arches with IRQ for each msg type (above), receiver can use IRQ-id to
+ * figure out what msg was sent. For those which don't (ARC has dedicated IPI
+ * IRQ), the msg-type needs to be conveyed via per-cpu data
+ */
-static DEFINE_PER_CPU(struct ipi_data, ipi_data);
+static DEFINE_PER_CPU(unsigned long, ipi_data);
-static void ipi_send_msg(const struct cpumask *callmap, enum ipi_msg_type msg)
+static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg)
{
+ unsigned long __percpu *ipi_data_ptr = per_cpu_ptr(&ipi_data, cpu);
+ unsigned long old, new;
unsigned long flags;
- unsigned int cpu;
+
+ pr_debug("%d Sending msg [%d] to %d\n", smp_processor_id(), msg, cpu);
local_irq_save(flags);
- for_each_cpu(cpu, callmap) {
- struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
- set_bit(msg, &ipi->bits);
- }
+ /*
+ * Atomically write new msg bit (in case others are writing too),
+ * and read back old value
+ */
+ do {
+ new = old = *ipi_data_ptr;
+ new |= 1U << msg;
+ } while (cmpxchg(ipi_data_ptr, old, new) != old);
- /* Call the platform specific cross-CPU call function */
- if (plat_smp_ops.ipi_send)
- plat_smp_ops.ipi_send((void *)callmap);
+ /*
+ * Call the platform specific IPI kick function, but avoid if possible:
+ * Only do so if there's no pending msg from other concurrent sender(s).
+ * Otherwise, recevier will see this msg as well when it takes the
+ * IPI corresponding to that msg. This is true, even if it is already in
+ * IPI handler, because !@old means it has not yet dequeued the msg(s)
+ * so @new msg can be a free-loader
+ */
+ if (plat_smp_ops.ipi_send && !old)
+ plat_smp_ops.ipi_send(cpu);
local_irq_restore(flags);
}
+static void ipi_send_msg(const struct cpumask *callmap, enum ipi_msg_type msg)
+{
+ unsigned int cpu;
+
+ for_each_cpu(cpu, callmap)
+ ipi_send_msg_one(cpu, msg);
+}
+
void smp_send_reschedule(int cpu)
{
- ipi_send_msg(cpumask_of(cpu), IPI_RESCHEDULE);
+ ipi_send_msg_one(cpu, IPI_RESCHEDULE);
}
void smp_send_stop(void)
@@ -254,7 +268,7 @@ void smp_send_stop(void)
void arch_send_call_function_single_ipi(int cpu)
{
- ipi_send_msg(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+ ipi_send_msg_one(cpu, IPI_CALL_FUNC);
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -265,37 +279,29 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
/*
* ipi_cpu_stop - handle IPI from smp_send_stop()
*/
-static void ipi_cpu_stop(unsigned int cpu)
+static void ipi_cpu_stop(void)
{
machine_halt();
}
-static inline void __do_IPI(unsigned long *ops, struct ipi_data *ipi, int cpu)
+static inline void __do_IPI(unsigned long msg)
{
- unsigned long msg = 0;
-
- do {
- msg = find_next_bit(ops, BITS_PER_LONG, msg+1);
+ switch (msg) {
+ case IPI_RESCHEDULE:
+ scheduler_ipi();
+ break;
- switch (msg) {
- case IPI_RESCHEDULE:
- scheduler_ipi();
- break;
-
- case IPI_CALL_FUNC:
- generic_smp_call_function_interrupt();
- break;
-
- case IPI_CALL_FUNC_SINGLE:
- generic_smp_call_function_single_interrupt();
- break;
+ case IPI_CALL_FUNC:
+ generic_smp_call_function_interrupt();
+ break;
- case IPI_CPU_STOP:
- ipi_cpu_stop(cpu);
- break;
- }
- } while (msg < BITS_PER_LONG);
+ case IPI_CPU_STOP:
+ ipi_cpu_stop();
+ break;
+ default:
+ pr_warn("IPI with unexpected msg %ld\n", msg);
+ }
}
/*
@@ -304,19 +310,25 @@ static inline void __do_IPI(unsigned long *ops, struct ipi_data *ipi, int cpu)
*/
irqreturn_t do_IPI(int irq, void *dev_id)
{
- int cpu = smp_processor_id();
- struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
- unsigned long ops;
+ unsigned long pending;
+
+ pr_debug("IPI [%ld] received on cpu %d\n",
+ *this_cpu_ptr(&ipi_data), smp_processor_id());
if (plat_smp_ops.ipi_clear)
- plat_smp_ops.ipi_clear(cpu, irq);
+ plat_smp_ops.ipi_clear(irq);
/*
- * XXX: is this loop really needed
- * And do we need to move ipi_clean inside
+ * "dequeue" the msg corresponding to this IPI (and possibly other
+ * piggybacked msg from elided IPIs: see ipi_send_msg_one() above)
*/
- while ((ops = xchg(&ipi->bits, 0)) != 0)
- __do_IPI(&ops, ipi, cpu);
+ pending = xchg(this_cpu_ptr(&ipi_data), 0);
+
+ do {
+ unsigned long msg = __ffs(pending);
+ __do_IPI(msg);
+ pending &= ~(1U << msg);
+ } while (pending);
return IRQ_HANDLED;
}
@@ -325,8 +337,19 @@ irqreturn_t do_IPI(int irq, void *dev_id)
* API called by platform code to hookup arch-common ISR to their IPI IRQ
*/
static DEFINE_PER_CPU(int, ipi_dev);
+
+static struct irqaction arc_ipi_irq = {
+ .name = "IPI Interrupt",
+ .flags = IRQF_PERCPU,
+ .handler = do_IPI,
+};
+
int smp_ipi_irq_setup(int cpu, int irq)
{
- int *dev_id = &per_cpu(ipi_dev, smp_processor_id());
- return request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev_id);
+ if (!cpu)
+ return setup_irq(irq, &arc_ipi_irq);
+ else
+ arch_unmask_irq(irq);
+
+ return 0;
}
diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
index a63ff842564..9ce47cfe230 100644
--- a/arch/arc/kernel/stacktrace.c
+++ b/arch/arc/kernel/stacktrace.c
@@ -79,7 +79,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
* assembly code
*/
frame_info->regs.r27 = 0;
- frame_info->regs.r28 += 64;
+ frame_info->regs.r28 += 60;
frame_info->call_frame = 0;
} else {
@@ -220,13 +220,6 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_stacktrace(tsk, NULL);
}
-/* Expected by Rest of kernel code */
-void dump_stack(void)
-{
- show_stacktrace(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
/* Another API expected by schedular, shows up in "ps" as Wait Channel
* Ofcourse just returning schedule( ) would be pointless so unwind until
* the function is not in schedular code
@@ -244,11 +237,14 @@ unsigned int get_wchan(struct task_struct *tsk)
*/
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
+ /* Assumes @tsk is sleeping so unwinds from __switch_to */
arc_unwind_core(tsk, NULL, __collect_all_but_sched, trace);
}
void save_stack_trace(struct stack_trace *trace)
{
- arc_unwind_core(current, NULL, __collect_all, trace);
+ /* Pass NULL for task so it unwinds the current call frame */
+ arc_unwind_core(NULL, NULL, __collect_all, trace);
}
+EXPORT_SYMBOL_GPL(save_stack_trace);
#endif
diff --git a/arch/arc/kernel/sys.c b/arch/arc/kernel/sys.c
index f6bdd07583f..9d6c1ca26af 100644
--- a/arch/arc/kernel/sys.c
+++ b/arch/arc/kernel/sys.c
@@ -6,8 +6,6 @@
#include <asm/syscalls.h>
#define sys_clone sys_clone_wrapper
-#define sys_fork sys_fork_wrapper
-#define sys_vfork sys_vfork_wrapper
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index f13f72807aa..36c2aa99436 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/timex.h>
@@ -45,17 +44,29 @@
#include <asm/clk.h>
#include <asm/mach_desc.h>
+/* Timer related Aux registers */
+#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */
+#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */
+#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */
+#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */
+#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */
+#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */
+
+#define TIMER_CTRL_IE (1 << 0) /* Interupt when Count reachs limit */
+#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */
+
#define ARC_TIMER_MAX 0xFFFFFFFF
/********** Clock Source Device *********/
#ifdef CONFIG_ARC_HAS_RTSC
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
{
- /* RTSC insn taps into cpu clk, needs no setup */
-
- /* For SMP, only allowed if cross-core-sync, hence usable as cs */
+ /*
+ * For SMP this needs to be 0. However Kconfig glue doesn't
+ * enable this option for SMP configs
+ */
return 1;
}
@@ -106,7 +117,7 @@ static bool is_usable_as_clocksource(void)
/*
* set 32bit TIMER1 to keep counting monotonically and wraparound
*/
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
{
write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
write_aux_reg(ARC_REG_TIMER1_CNT, 0);
@@ -144,22 +155,6 @@ static void arc_timer_event_setup(unsigned int limit)
write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH);
}
-/*
- * Acknowledge the interrupt (oneshot) and optionally re-arm it (periodic)
- * -Any write to CTRL Reg will ack the intr (NH bit: Count when not halted)
- * -Rearming is done by setting the IE bit
- *
- * Small optimisation: Normal code would have been
- * if (irq_reenable)
- * CTRL_REG = (IE | NH);
- * else
- * CTRL_REG = NH;
- * However since IE is BIT0 we can fold the branch
- */
-static void arc_timer_event_ack(unsigned int irq_reenable)
-{
- write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
-}
static int arc_clkevent_set_next_event(unsigned long delta,
struct clock_event_device *dev)
@@ -196,10 +191,22 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
static irqreturn_t timer_irq_handler(int irq, void *dev_id)
{
- struct clock_event_device *clk = &__get_cpu_var(arc_clockevent_device);
+ /*
+ * Note that generic IRQ core could have passed @evt for @dev_id if
+ * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
+ */
+ struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
+ int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+
+ /*
+ * Any write to CTRL reg ACks the interrupt, we rewrite the
+ * Count when [N]ot [H]alted bit.
+ * And re-arm it if perioid by [I]nterrupt [E]nable bit
+ */
+ write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
+
+ evt->event_handler(evt);
- arc_timer_event_ack(clk->mode == CLOCK_EVT_MODE_PERIODIC);
- clk->event_handler(clk);
return IRQ_HANDLED;
}
@@ -211,18 +218,15 @@ static struct irqaction arc_timer_irq = {
/*
* Setup the local event timer for @cpu
- * N.B. weak so that some exotic ARC SoCs can completely override it
*/
-void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu)
+void arc_local_timer_setup()
{
- struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
-
- clockevents_calc_mult_shift(clk, arc_get_core_freq(), 5);
-
- clk->max_delta_ns = clockevent_delta2ns(ARC_TIMER_MAX, clk);
- clk->cpumask = cpumask_of(cpu);
+ struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
+ int cpu = smp_processor_id();
- clockevents_register_device(clk);
+ evt->cpumask = cpumask_of(cpu);
+ clockevents_config_and_register(evt, arc_get_core_freq(),
+ 0, ARC_TIMER_MAX);
/*
* setup the per-cpu timer IRQ handler - for all cpus
@@ -258,7 +262,7 @@ void __init time_init(void)
clocksource_register_hz(&arc_counter, arc_get_core_freq());
/* sets up the periodic event timer */
- arc_local_timer_setup(smp_processor_id());
+ arc_local_timer_setup();
if (machine_desc->init_time)
machine_desc->init_time();
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index 7496995371e..3eadfdabc32 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -16,21 +16,21 @@
#include <linux/sched.h>
#include <linux/kdebug.h>
#include <linux/uaccess.h>
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
+#include <linux/kprobes.h>
+#include <linux/kgdb.h>
#include <asm/setup.h>
-#include <asm/kprobes.h>
#include <asm/unaligned.h>
-#include <asm/kgdb.h>
+#include <asm/kprobes.h>
void __init trap_init(void)
{
return;
}
-void die(const char *str, struct pt_regs *regs, unsigned long address,
- unsigned long cause_reg)
+void die(const char *str, struct pt_regs *regs, unsigned long address)
{
- show_kernel_fault_diag(str, regs, address, cause_reg);
+ show_kernel_fault_diag(str, regs, address);
/* DEAD END */
__asm__("flag 1");
@@ -41,14 +41,13 @@ void die(const char *str, struct pt_regs *regs, unsigned long address,
* -for user faults enqueues requested signal
* -for kernel, chk if due to copy_(to|from)_user, otherwise die()
*/
-static noinline int handle_exception(unsigned long cause, char *str,
- struct pt_regs *regs, siginfo_t *info)
+static noinline int
+handle_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
{
if (user_mode(regs)) {
struct task_struct *tsk = current;
tsk->thread.fault_address = (__force unsigned int)info->si_addr;
- tsk->thread.cause_code = cause;
force_sig_info(info->si_signo, info, tsk);
@@ -57,14 +56,14 @@ static noinline int handle_exception(unsigned long cause, char *str,
if (fixup_exception(regs))
return 0;
- die(str, regs, (unsigned long)info->si_addr, cause);
+ die(str, regs, (unsigned long)info->si_addr);
}
return 1;
}
#define DO_ERROR_INFO(signr, str, name, sicode) \
-int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
+int name(unsigned long address, struct pt_regs *regs) \
{ \
siginfo_t info = { \
.si_signo = signr, \
@@ -72,7 +71,7 @@ int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
.si_code = sicode, \
.si_addr = (void __user *)address, \
}; \
- return handle_exception(cause, str, regs, &info);\
+ return handle_exception(str, regs, &info);\
}
/*
@@ -83,39 +82,28 @@ DO_ERROR_INFO(SIGILL, "Invalid Extn Insn", do_extension_fault, ILL_ILLOPC)
DO_ERROR_INFO(SIGILL, "Illegal Insn (or Seq)", insterror_is_error, ILL_ILLOPC)
DO_ERROR_INFO(SIGBUS, "Invalid Mem Access", do_memory_error, BUS_ADRERR)
DO_ERROR_INFO(SIGTRAP, "Breakpoint Set", trap_is_brkpt, TRAP_BRKPT)
+DO_ERROR_INFO(SIGBUS, "Misaligned Access", do_misaligned_error, BUS_ADRALN)
-#ifdef CONFIG_ARC_MISALIGN_ACCESS
/*
* Entry Point for Misaligned Data access Exception, for emulating in software
*/
-int do_misaligned_access(unsigned long cause, unsigned long address,
- struct pt_regs *regs, struct callee_regs *cregs)
+int do_misaligned_access(unsigned long address, struct pt_regs *regs,
+ struct callee_regs *cregs)
{
- if (misaligned_fixup(address, regs, cause, cregs) != 0) {
- siginfo_t info;
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRALN;
- info.si_addr = (void __user *)address;
- return handle_exception(cause, "Misaligned Access", regs,
- &info);
- }
+ /* If emulation not enabled, or failed, kill the task */
+ if (misaligned_fixup(address, regs, cregs) != 0)
+ return do_misaligned_error(address, regs);
+
return 0;
}
-#else
-DO_ERROR_INFO(SIGSEGV, "Misaligned Access", do_misaligned_access, SEGV_ACCERR)
-#endif
-
/*
* Entry point for miscll errors such as Nested Exceptions
* -Duplicate TLB entry is handled seperately though
*/
-void do_machine_check_fault(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
{
- die("Machine Check Exception", regs, address, cause);
+ die("Machine Check Exception", regs, address);
}
@@ -128,23 +116,22 @@ void do_machine_check_fault(unsigned long cause, unsigned long address,
* -1 used for software breakpointing (gdb)
* -2 used by kprobes
*/
-void do_non_swi_trap(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
{
- unsigned int param = cause & 0xff;
+ unsigned int param = regs->ecr_param;
switch (param) {
case 1:
- trap_is_brkpt(cause, address, regs);
+ trap_is_brkpt(address, regs);
break;
case 2:
- trap_is_kprobe(param, address, regs);
+ trap_is_kprobe(address, regs);
break;
case 3:
case 4:
- kgdb_trap(regs, param);
+ kgdb_trap(regs);
break;
default:
@@ -157,14 +144,14 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
* -For a corner case, ARC kprobes implementation resorts to using
* this exception, hence the check
*/
-void do_insterror_or_kprobe(unsigned long cause,
- unsigned long address,
- struct pt_regs *regs)
+void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
{
+ int rc;
+
/* Check if this exception is caused by kprobes */
- if (notify_die(DIE_IERR, "kprobe_ierr", regs, address,
- cause, SIGILL) == NOTIFY_STOP)
+ rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
+ if (rc == NOTIFY_STOP)
return;
- insterror_is_error(cause, address, regs);
+ insterror_is_error(address, regs);
}
diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 7c10873c311..1badf9b84b5 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -26,7 +26,6 @@ static noinline void print_reg_file(long *reg_rev, int start_num)
char buf[512];
int n = 0, len = sizeof(buf);
- /* weird loop because pt_regs regs rev r12..r0, r25..r13 */
for (i = start_num; i < start_num + 13; i++) {
n += scnprintf(buf + n, len - n, "r%02u: 0x%08lx\t",
i, (unsigned long)*reg_rev);
@@ -34,13 +33,18 @@ static noinline void print_reg_file(long *reg_rev, int start_num)
if (((i + 1) % 3) == 0)
n += scnprintf(buf + n, len - n, "\n");
+ /* because pt_regs has regs reversed: r12..r0, r25..r13 */
reg_rev--;
}
if (start_num != 0)
n += scnprintf(buf + n, len - n, "\n\n");
- pr_info("%s", buf);
+ /* To continue printing callee regs on same line as scratch regs */
+ if (start_num == 0)
+ pr_info("%s", buf);
+ else
+ pr_cont("%s\n", buf);
}
static void show_callee_regs(struct callee_regs *cregs)
@@ -71,7 +75,7 @@ void print_task_path_n_nm(struct task_struct *tsk, char *buf)
}
done:
- pr_info("%s, TGID %u\n", path_nm, tsk->tgid);
+ pr_info("Path: %s\n", path_nm);
}
EXPORT_SYMBOL(print_task_path_n_nm);
@@ -82,8 +86,13 @@ static void show_faulting_vma(unsigned long address, char *buf)
unsigned long ino = 0;
dev_t dev = 0;
char *nm = buf;
+ struct mm_struct *active_mm = current->active_mm;
- vma = find_vma(current->active_mm, address);
+ /* can't use print_vma_addr() yet as it doesn't check for
+ * non-inclusive vma
+ */
+ down_read(&active_mm->mmap_sem);
+ vma = find_vma(active_mm, address);
/* check against the find_vma( ) behaviour which returns the next VMA
* if the container VMA is not found
@@ -93,36 +102,39 @@ static void show_faulting_vma(unsigned long address, char *buf)
if (file) {
struct path *path = &file->f_path;
nm = d_path(path, buf, PAGE_SIZE - 1);
- inode = vma->vm_file->f_path.dentry->d_inode;
+ inode = file_inode(vma->vm_file);
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
pr_info(" @off 0x%lx in [%s]\n"
- " VMA: 0x%08lx to 0x%08lx\n\n",
- address - vma->vm_start, nm, vma->vm_start, vma->vm_end);
+ " VMA: 0x%08lx to 0x%08lx\n",
+ vma->vm_start < TASK_UNMAPPED_BASE ?
+ address : address - vma->vm_start,
+ nm, vma->vm_start, vma->vm_end);
} else
pr_info(" @No matching VMA found\n");
+
+ up_read(&active_mm->mmap_sem);
}
static void show_ecr_verbose(struct pt_regs *regs)
{
- unsigned int vec, cause_code, cause_reg;
+ unsigned int vec, cause_code;
unsigned long address;
- cause_reg = current->thread.cause_code;
- pr_info("\n[ECR]: 0x%08x => ", cause_reg);
+ pr_info("\n[ECR ]: 0x%08lx => ", regs->event);
/* For Data fault, this is data address not instruction addr */
address = current->thread.fault_address;
- vec = cause_reg >> 16;
- cause_code = (cause_reg >> 8) & 0xFF;
+ vec = regs->ecr_vec;
+ cause_code = regs->ecr_cause;
/* For DTLB Miss or ProtV, display the memory involved too */
if (vec == ECR_V_DTLB_MISS) {
- pr_cont("Invalid (%s) @ 0x%08lx by insn @ 0x%08lx\n",
- (cause_code == 0x01) ? "Read From" :
- ((cause_code == 0x02) ? "Write to" : "EX"),
+ pr_cont("Invalid %s @ 0x%08lx by insn @ 0x%08lx\n",
+ (cause_code == 0x01) ? "Read" :
+ ((cause_code == 0x02) ? "Write" : "EX"),
address, regs->ret);
} else if (vec == ECR_V_ITLB_MISS) {
pr_cont("Insn could not be fetched\n");
@@ -133,14 +145,12 @@ static void show_ecr_verbose(struct pt_regs *regs)
} else if (vec == ECR_V_PROTV) {
if (cause_code == ECR_C_PROTV_INST_FETCH)
pr_cont("Execute from Non-exec Page\n");
- else if (cause_code == ECR_C_PROTV_LOAD)
- pr_cont("Read from Non-readable Page\n");
- else if (cause_code == ECR_C_PROTV_STORE)
- pr_cont("Write to Non-writable Page\n");
- else if (cause_code == ECR_C_PROTV_XCHG)
- pr_cont("Data exchange protection violation\n");
else if (cause_code == ECR_C_PROTV_MISALIG_DATA)
pr_cont("Misaligned r/w from 0x%08lx\n", address);
+ else
+ pr_cont("%s access not allowed on page\n",
+ (cause_code == 0x01) ? "Read" :
+ ((cause_code == 0x02) ? "Write" : "EX"));
} else if (vec == ECR_V_INSN_ERR) {
pr_cont("Illegal Insn\n");
} else {
@@ -163,24 +173,27 @@ void show_regs(struct pt_regs *regs)
return;
print_task_path_n_nm(tsk, buf);
+ show_regs_print_info(KERN_INFO);
- if (current->thread.cause_code)
- show_ecr_verbose(regs);
+ show_ecr_verbose(regs);
- pr_info("[EFA]: 0x%08lx\n", current->thread.fault_address);
- pr_info("[ERET]: 0x%08lx (PC of Faulting Instr)\n", regs->ret);
+ pr_info("[EFA ]: 0x%08lx\n[BLINK ]: %pS\n[ERET ]: %pS\n",
+ current->thread.fault_address,
+ (void *)regs->blink, (void *)regs->ret);
- show_faulting_vma(regs->ret, buf); /* faulting code, not data */
+ if (user_mode(regs))
+ show_faulting_vma(regs->ret, buf); /* faulting code, not data */
- /* can't use print_vma_addr() yet as it doesn't check for
- * non-inclusive vma
- */
+ pr_info("[STAT32]: 0x%08lx", regs->status32);
+
+#define STS_BIT(r, bit) r->status32 & STATUS_##bit##_MASK ? #bit : ""
+ if (!user_mode(regs))
+ pr_cont(" : %2s %2s %2s %2s %2s\n",
+ STS_BIT(regs, AE), STS_BIT(regs, A2), STS_BIT(regs, A1),
+ STS_BIT(regs, E2), STS_BIT(regs, E1));
- /* print special regs */
- pr_info("status32: 0x%08lx\n", regs->status32);
- pr_info(" SP: 0x%08lx\tFP: 0x%08lx\n", regs->sp, regs->fp);
- pr_info("BTA: 0x%08lx\tBLINK: 0x%08lx\n",
- regs->bta, regs->blink);
+ pr_info("BTA: 0x%08lx\t SP: 0x%08lx\t FP: 0x%08lx\n",
+ regs->bta, regs->sp, regs->fp);
pr_info("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n",
regs->lp_start, regs->lp_end, regs->lp_count);
@@ -198,10 +211,9 @@ void show_regs(struct pt_regs *regs)
}
void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
- unsigned long address, unsigned long cause_reg)
+ unsigned long address)
{
current->thread.fault_address = address;
- current->thread.cause_code = cause_reg;
/* Caller and Callee regs */
show_regs(regs);
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c
index 4cd81633feb..7ff5b5c183b 100644
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -16,6 +16,16 @@
#include <linux/uaccess.h>
#include <asm/disasm.h>
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define BE 1
+#define FIRST_BYTE_16 "swap %1, %1\n swape %1, %1\n"
+#define FIRST_BYTE_32 "swape %1, %1\n"
+#else
+#define BE 0
+#define FIRST_BYTE_16
+#define FIRST_BYTE_32
+#endif
+
#define __get8_unaligned_check(val, addr, err) \
__asm__( \
"1: ldb.ab %1, [%2, 1]\n" \
@@ -36,9 +46,9 @@
do { \
unsigned int err = 0, v, a = addr; \
__get8_unaligned_check(v, a, err); \
- val = v ; \
+ val = v << ((BE) ? 8 : 0); \
__get8_unaligned_check(v, a, err); \
- val |= v << 8; \
+ val |= v << ((BE) ? 0 : 8); \
if (err) \
goto fault; \
} while (0)
@@ -47,13 +57,13 @@
do { \
unsigned int err = 0, v, a = addr; \
__get8_unaligned_check(v, a, err); \
- val = v << 0; \
+ val = v << ((BE) ? 24 : 0); \
__get8_unaligned_check(v, a, err); \
- val |= v << 8; \
+ val |= v << ((BE) ? 16 : 8); \
__get8_unaligned_check(v, a, err); \
- val |= v << 16; \
+ val |= v << ((BE) ? 8 : 16); \
__get8_unaligned_check(v, a, err); \
- val |= v << 24; \
+ val |= v << ((BE) ? 0 : 24); \
if (err) \
goto fault; \
} while (0)
@@ -63,6 +73,7 @@
unsigned int err = 0, v = val, a = addr;\
\
__asm__( \
+ FIRST_BYTE_16 \
"1: stb.ab %1, [%2, 1]\n" \
" lsr %1, %1, 8\n" \
"2: stb %1, [%2]\n" \
@@ -87,8 +98,9 @@
#define put32_unaligned_check(val, addr) \
do { \
unsigned int err = 0, v = val, a = addr;\
- __asm__( \
\
+ __asm__( \
+ FIRST_BYTE_32 \
"1: stb.ab %1, [%2, 1]\n" \
" lsr %1, %1, 8\n" \
"2: stb.ab %1, [%2, 1]\n" \
@@ -187,7 +199,7 @@ fault: state->fault = 1;
* Returns 0 if successfully handled, 1 if some error happened
*/
int misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs)
+ struct callee_regs *cregs)
{
struct disasm_state state;
char buf[TASK_COMM_LEN];
@@ -233,6 +245,12 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
regs->status32 &= ~STATUS_DE_MASK;
} else {
regs->ret += state.instr_len;
+
+ /* handle zero-overhead-loop */
+ if ((regs->ret == regs->lp_end) && (regs->lp_count)) {
+ regs->ret = regs->lp_start;
+ regs->lp_count--;
+ }
}
return 0;
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index a8d02223da4..e550b117ec4 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -289,6 +289,8 @@ static void __init setup_unwind_table(struct unwind_table *table,
* instead of the initial loc addr
* return;
*/
+ WARN(1, "unwinder: FDE->initial_location NULL %p\n",
+ (const u8 *)(fde + 1) + *fde);
}
++n;
}
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index d3c92f52d44..dd35bde39f6 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -116,7 +116,7 @@ SECTIONS
_edata = .;
- BSS_SECTION(0, 0, 0)
+ BSS_SECTION(4, 4, 4)
#ifdef CONFIG_ARC_DW2_UNWIND
. = ALIGN(PAGE_SIZE);
@@ -125,6 +125,11 @@ SECTIONS
*(.debug_frame)
__end_unwind = .;
}
+ /*
+ * gcc 4.8 generates this for -fasynchonous-unwind-tables,
+ * while we still use the .debug_frame based unwinder
+ */
+ /DISCARD/ : { *(.eh_frame) }
#else
/DISCARD/ : { *(.debug_frame) }
#endif
@@ -142,15 +147,18 @@ SECTIONS
*(.arcextmap.*)
}
+#ifndef CONFIG_DEBUG_INFO
/* open-coded because we need .debug_frame seperately for unwinding */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
+ /DISCARD/ : { *(.debug_aranges) }
+ /DISCARD/ : { *(.debug_pubnames) }
+ /DISCARD/ : { *(.debug_info) }
+ /DISCARD/ : { *(.debug_abbrev) }
+ /DISCARD/ : { *(.debug_line) }
+ /DISCARD/ : { *(.debug_str) }
+ /DISCARD/ : { *(.debug_loc) }
+ /DISCARD/ : { *(.debug_macinfo) }
+ /DISCARD/ : { *(.debug_ranges) }
+#endif
#ifdef CONFIG_ARC_HAS_DCCM
. = CONFIG_ARC_DCCM_BASE;
diff --git a/arch/arc/lib/memcmp.S b/arch/arc/lib/memcmp.S
index bc813d55b6c..978bf8314df 100644
--- a/arch/arc/lib/memcmp.S
+++ b/arch/arc/lib/memcmp.S
@@ -6,7 +6,7 @@
* published by the Free Software Foundation.
*/
-#include <asm/linkage.h>
+#include <linux/linkage.h>
#ifdef __LITTLE_ENDIAN__
#define WORD2 r2
@@ -16,7 +16,7 @@
#define SHIFT r2
#endif
-ARC_ENTRY memcmp
+ENTRY(memcmp)
or r12,r0,r1
asl_s r12,r12,30
sub r3,r2,1
@@ -121,4 +121,4 @@ ARC_ENTRY memcmp
.Lnil:
j_s.d [blink]
mov r0,0
-ARC_EXIT memcmp
+END(memcmp)
diff --git a/arch/arc/lib/memcpy-700.S b/arch/arc/lib/memcpy-700.S
index b64cc10ac91..3222573e50d 100644
--- a/arch/arc/lib/memcpy-700.S
+++ b/arch/arc/lib/memcpy-700.S
@@ -6,9 +6,9 @@
* published by the Free Software Foundation.
*/
-#include <asm/linkage.h>
+#include <linux/linkage.h>
-ARC_ENTRY memcpy
+ENTRY(memcpy)
or r3,r0,r1
asl_s r3,r3,30
mov_s r5,r0
@@ -63,4 +63,4 @@ ARC_ENTRY memcpy
.Lendbloop:
j_s.d [blink]
stb r12,[r5,0]
-ARC_EXIT memcpy
+END(memcpy)
diff --git a/arch/arc/lib/memset.S b/arch/arc/lib/memset.S
index 9b2d88d2e14..d36bd43fc98 100644
--- a/arch/arc/lib/memset.S
+++ b/arch/arc/lib/memset.S
@@ -6,11 +6,11 @@
* published by the Free Software Foundation.
*/
-#include <asm/linkage.h>
+#include <linux/linkage.h>
#define SMALL 7 /* Must be at least 6 to deal with alignment/loop issues. */
-ARC_ENTRY memset
+ENTRY(memset)
mov_s r4,r0
or r12,r0,r2
bmsk.f r12,r12,1
@@ -46,14 +46,14 @@ ARC_ENTRY memset
stb.ab r1,[r4,1]
.Ltiny_end:
j_s [blink]
-ARC_EXIT memset
+END(memset)
; memzero: @r0 = mem, @r1 = size_t
; memset: @r0 = mem, @r1 = char, @r2 = size_t
-ARC_ENTRY memzero
+ENTRY(memzero)
; adjust bzero args to memset args
mov r2, r1
mov r1, 0
b memset ;tail call so need to tinker with blink
-ARC_EXIT memzero
+END(memzero)
diff --git a/arch/arc/lib/strchr-700.S b/arch/arc/lib/strchr-700.S
index 99c10475d47..b725d586210 100644
--- a/arch/arc/lib/strchr-700.S
+++ b/arch/arc/lib/strchr-700.S
@@ -11,9 +11,9 @@
presence of the norm instruction makes it easier to operate on whole
words branch-free. */
-#include <asm/linkage.h>
+#include <linux/linkage.h>
-ARC_ENTRY strchr
+ENTRY(strchr)
extb_s r1,r1
asl r5,r1,8
bmsk r2,r0,1
@@ -39,9 +39,18 @@ ARC_ENTRY strchr
ld.a r2,[r0,4]
sub r12,r6,r7
bic r12,r12,r6
+#ifdef __LITTLE_ENDIAN__
and r7,r12,r4
breq r7,0,.Loop ; For speed, we want this branch to be unaligned.
b .Lfound_char ; Likewise this one.
+#else
+ and r12,r12,r4
+ breq r12,0,.Loop ; For speed, we want this branch to be unaligned.
+ lsr_s r12,r12,7
+ bic r2,r7,r6
+ b.d .Lfound_char_b
+ and_s r2,r2,r12
+#endif
; /* We require this code address to be unaligned for speed... */
.Laligned:
ld_s r2,[r0]
@@ -95,6 +104,7 @@ ARC_ENTRY strchr
lsr r7,r7,7
bic r2,r7,r6
+.Lfound_char_b:
norm r2,r2
sub_s r0,r0,4
asr_s r2,r2,3
@@ -120,4 +130,4 @@ ARC_ENTRY strchr
j_s.d [blink]
mov.mi r0,0
#endif /* ENDIAN */
-ARC_EXIT strchr
+END(strchr)
diff --git a/arch/arc/lib/strcmp.S b/arch/arc/lib/strcmp.S
index 5dc802b45cf..3544600fefe 100644
--- a/arch/arc/lib/strcmp.S
+++ b/arch/arc/lib/strcmp.S
@@ -13,9 +13,9 @@
source 1; however, that would increase the overhead for loop setup / finish,
and strcmp might often terminate early. */
-#include <asm/linkage.h>
+#include <linux/linkage.h>
-ARC_ENTRY strcmp
+ENTRY(strcmp)
or r2,r0,r1
bmsk_s r2,r2,1
brne r2,0,.Lcharloop
@@ -93,4 +93,4 @@ ARC_ENTRY strcmp
.Lcmpend:
j_s.d [blink]
sub r0,r2,r3
-ARC_EXIT strcmp
+END(strcmp)
diff --git a/arch/arc/lib/strcpy-700.S b/arch/arc/lib/strcpy-700.S
index b7ca4ae81d8..8422f38e121 100644
--- a/arch/arc/lib/strcpy-700.S
+++ b/arch/arc/lib/strcpy-700.S
@@ -16,9 +16,9 @@
there, but the it is not likely to be taken often, and it
would also be likey to cost an unaligned mispredict at the next call. */
-#include <asm/linkage.h>
+#include <linux/linkage.h>
-ARC_ENTRY strcpy
+ENTRY(strcpy)
or r2,r0,r1
bmsk_s r2,r2,1
brne.d r2,0,charloop
@@ -67,4 +67,4 @@ charloop:
brne.d r3,0,charloop
stb.ab r3,[r10,1]
j [blink]
-ARC_EXIT strcpy
+END(strcpy)
diff --git a/arch/arc/lib/strlen.S b/arch/arc/lib/strlen.S
index 39759e09969..53cfd5685a5 100644
--- a/arch/arc/lib/strlen.S
+++ b/arch/arc/lib/strlen.S
@@ -6,9 +6,9 @@
* published by the Free Software Foundation.
*/
-#include <asm/linkage.h>
+#include <linux/linkage.h>
-ARC_ENTRY strlen
+ENTRY(strlen)
or r3,r0,7
ld r2,[r3,-7]
ld.a r6,[r3,-3]
@@ -80,4 +80,4 @@ ARC_ENTRY strlen
.Learly_end:
b.d .Lend
sub_s.ne r1,r1,r1
-ARC_EXIT strlen
+END(strlen)
diff --git a/arch/arc/mm/Makefile b/arch/arc/mm/Makefile
index 168dc146a8f..ac95cc239c1 100644
--- a/arch/arc/mm/Makefile
+++ b/arch/arc/mm/Makefile
@@ -7,4 +7,4 @@
#
obj-y := extable.o ioremap.o dma.o fault.o init.o
-obj-y += tlb.o tlbex.o cache_arc700.o
+obj-y += tlb.o tlbex.o cache_arc700.o mmap.o
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index 88d617d8423..353b202c37c 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -68,24 +68,14 @@
#include <linux/mmu_context.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/pagemap.h>
#include <asm/cacheflush.h>
#include <asm/cachectl.h>
#include <asm/setup.h>
-
-#ifdef CONFIG_ARC_HAS_ICACHE
-static void __ic_line_inv_no_alias(unsigned long, int);
-static void __ic_line_inv_2_alias(unsigned long, int);
-static void __ic_line_inv_4_alias(unsigned long, int);
-
-/* Holds the ptr to flush routine, dependign on size due to aliasing issues */
-static void (*___flush_icache_rtn) (unsigned long, int);
-#endif
-
-char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
+char *arc_cache_mumbojumbo(int c, char *buf, int len)
{
int n = 0;
- unsigned int c = smp_processor_id();
#define PR_CACHE(p, enb, str) \
{ \
@@ -98,8 +88,10 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
enb ? "" : "DISABLED (kernel-build)"); \
}
- PR_CACHE(&cpuinfo_arc700[c].icache, __CONFIG_ARC_HAS_ICACHE, "I-Cache");
- PR_CACHE(&cpuinfo_arc700[c].dcache, __CONFIG_ARC_HAS_DCACHE, "D-Cache");
+ PR_CACHE(&cpuinfo_arc700[c].icache, IS_ENABLED(CONFIG_ARC_HAS_ICACHE),
+ "I-Cache");
+ PR_CACHE(&cpuinfo_arc700[c].dcache, IS_ENABLED(CONFIG_ARC_HAS_DCACHE),
+ "D-Cache");
return buf;
}
@@ -109,17 +101,23 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
* the cpuinfo structure for later use.
* No Validation done here, simply read/convert the BCRs
*/
-void __init read_decode_cache_bcr(void)
+void read_decode_cache_bcr(void)
{
- struct bcr_cache ibcr, dbcr;
struct cpuinfo_arc_cache *p_ic, *p_dc;
unsigned int cpu = smp_processor_id();
+ struct bcr_cache {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
+#else
+ unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
+#endif
+ } ibcr, dbcr;
p_ic = &cpuinfo_arc700[cpu].icache;
READ_BCR(ARC_REG_IC_BCR, ibcr);
- if (ibcr.config == 0x3)
- p_ic->assoc = 2;
+ BUG_ON(ibcr.config != 3);
+ p_ic->assoc = 2; /* Fixed to 2w set assoc */
p_ic->line_len = 8 << ibcr.line_len;
p_ic->sz = 0x200 << ibcr.sz;
p_ic->ver = ibcr.ver;
@@ -127,8 +125,8 @@ void __init read_decode_cache_bcr(void)
p_dc = &cpuinfo_arc700[cpu].dcache;
READ_BCR(ARC_REG_DC_BCR, dbcr);
- if (dbcr.config == 0x2)
- p_dc->assoc = 4;
+ BUG_ON(dbcr.config != 2);
+ p_dc->assoc = 4; /* Fixed to 4w set assoc */
p_dc->line_len = 16 << dbcr.line_len;
p_dc->sz = 0x200 << dbcr.sz;
p_dc->ver = dbcr.ver;
@@ -141,112 +139,116 @@ void __init read_decode_cache_bcr(void)
* 3. Enable the Caches, setup default flush mode for D-Cache
* 3. Calculate the SHMLBA used by user space
*/
-void __init arc_cache_init(void)
+void arc_cache_init(void)
{
- unsigned int temp;
- unsigned int cpu = smp_processor_id();
- struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
- struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;
- int way_pg_ratio = way_pg_ratio;
+ unsigned int __maybe_unused cpu = smp_processor_id();
+ struct cpuinfo_arc_cache __maybe_unused *ic, __maybe_unused *dc;
char str[256];
printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
- if (!ic->ver)
- goto chk_dc;
-
#ifdef CONFIG_ARC_HAS_ICACHE
- /* 1. Confirm some of I-cache params which Linux assumes */
- if ((ic->assoc != ARC_ICACHE_WAYS) ||
- (ic->line_len != ARC_ICACHE_LINE_LEN)) {
- panic("Cache H/W doesn't match kernel Config");
- }
-#if (CONFIG_ARC_MMU_VER > 2)
- if (ic->ver != 3) {
- if (running_on_hw)
- panic("Cache ver doesn't match MMU ver\n");
-
- /* For ISS - suggest the toggles to use */
- pr_err("Use -prop=icache_version=3,-prop=dcache_version=3\n");
-
+ ic = &cpuinfo_arc700[cpu].icache;
+ if (ic->ver) {
+ if (ic->line_len != L1_CACHE_BYTES)
+ panic("ICache line [%d] != kernel Config [%d]",
+ ic->line_len, L1_CACHE_BYTES);
+
+ if (ic->ver != CONFIG_ARC_MMU_VER)
+ panic("Cache ver [%d] doesn't match MMU ver [%d]\n",
+ ic->ver, CONFIG_ARC_MMU_VER);
}
#endif
- /*
- * if Cache way size is <= page size then no aliasing exhibited
- * otherwise ratio determines num of aliases.
- * e.g. 32K I$, 2 way set assoc, 8k pg size
- * way-sz = 32k/2 = 16k
- * way-pg-ratio = 16k/8k = 2, so 2 aliases possible
- * (meaning 1 line could be in 2 possible locations).
- */
- way_pg_ratio = ic->sz / ARC_ICACHE_WAYS / PAGE_SIZE;
- switch (way_pg_ratio) {
- case 0:
- case 1:
- ___flush_icache_rtn = __ic_line_inv_no_alias;
- break;
- case 2:
- ___flush_icache_rtn = __ic_line_inv_2_alias;
- break;
- case 4:
- ___flush_icache_rtn = __ic_line_inv_4_alias;
- break;
- default:
- panic("Unsupported I-Cache Sz\n");
- }
-#endif
+#ifdef CONFIG_ARC_HAS_DCACHE
+ dc = &cpuinfo_arc700[cpu].dcache;
+ if (dc->ver) {
+ unsigned int dcache_does_alias;
- /* Enable/disable I-Cache */
- temp = read_aux_reg(ARC_REG_IC_CTRL);
+ if (dc->line_len != L1_CACHE_BYTES)
+ panic("DCache line [%d] != kernel Config [%d]",
+ dc->line_len, L1_CACHE_BYTES);
-#ifdef CONFIG_ARC_HAS_ICACHE
- temp &= ~IC_CTRL_CACHE_DISABLE;
-#else
- temp |= IC_CTRL_CACHE_DISABLE;
+ /* check for D-Cache aliasing */
+ dcache_does_alias = (dc->sz / dc->assoc) > PAGE_SIZE;
+
+ if (dcache_does_alias && !cache_is_vipt_aliasing())
+ panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
+ else if (!dcache_does_alias && cache_is_vipt_aliasing())
+ panic("Don't need CONFIG_ARC_CACHE_VIPT_ALIASING\n");
+ }
#endif
+}
- write_aux_reg(ARC_REG_IC_CTRL, temp);
+#define OP_INV 0x1
+#define OP_FLUSH 0x2
+#define OP_FLUSH_N_INV 0x3
+#define OP_INV_IC 0x4
-chk_dc:
- if (!dc->ver)
- return;
+/*
+ * Common Helper for Line Operations on {I,D}-Cache
+ */
+static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
+ unsigned long sz, const int cacheop)
+{
+ unsigned int aux_cmd, aux_tag;
+ int num_lines;
+ const int full_page_op = __builtin_constant_p(sz) && sz == PAGE_SIZE;
-#ifdef CONFIG_ARC_HAS_DCACHE
- if ((dc->assoc != ARC_DCACHE_WAYS) ||
- (dc->line_len != ARC_DCACHE_LINE_LEN)) {
- panic("Cache H/W doesn't match kernel Config");
+ if (cacheop == OP_INV_IC) {
+ aux_cmd = ARC_REG_IC_IVIL;
+#if (CONFIG_ARC_MMU_VER > 2)
+ aux_tag = ARC_REG_IC_PTAG;
+#endif
}
-
- /* check for D-Cache aliasing */
- if ((dc->sz / ARC_DCACHE_WAYS) > PAGE_SIZE)
- panic("D$ aliasing not handled right now\n");
+ else {
+ /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
+ aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
+#if (CONFIG_ARC_MMU_VER > 2)
+ aux_tag = ARC_REG_DC_PTAG;
#endif
+ }
- /* Set the default Invalidate Mode to "simpy discard dirty lines"
- * as this is more frequent then flush before invalidate
- * Ofcourse we toggle this default behviour when desired
+ /* Ensure we properly floor/ceil the non-line aligned/sized requests
+ * and have @paddr - aligned to cache line and integral @num_lines.
+ * This however can be avoided for page sized since:
+ * -@paddr will be cache-line aligned already (being page aligned)
+ * -@sz will be integral multiple of line size (being page sized).
*/
- temp = read_aux_reg(ARC_REG_DC_CTRL);
- temp &= ~DC_CTRL_INV_MODE_FLUSH;
+ if (!full_page_op) {
+ sz += paddr & ~CACHE_LINE_MASK;
+ paddr &= CACHE_LINE_MASK;
+ vaddr &= CACHE_LINE_MASK;
+ }
-#ifdef CONFIG_ARC_HAS_DCACHE
- /* Enable D-Cache: Clear Bit 0 */
- write_aux_reg(ARC_REG_DC_CTRL, temp & ~IC_CTRL_CACHE_DISABLE);
+ num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);
+
+#if (CONFIG_ARC_MMU_VER <= 2)
+ /* MMUv2 and before: paddr contains stuffed vaddrs bits */
+ paddr |= (vaddr >> PAGE_SHIFT) & 0x1F;
#else
- /* Flush D cache */
- write_aux_reg(ARC_REG_DC_FLSH, 0x1);
- /* Disable D cache */
- write_aux_reg(ARC_REG_DC_CTRL, temp | IC_CTRL_CACHE_DISABLE);
+ /* if V-P const for loop, PTAG can be written once outside loop */
+ if (full_page_op)
+ write_aux_reg(aux_tag, paddr);
#endif
- return;
+ while (num_lines-- > 0) {
+#if (CONFIG_ARC_MMU_VER > 2)
+ /* MMUv3, cache ops require paddr seperately */
+ if (!full_page_op) {
+ write_aux_reg(aux_tag, paddr);
+ paddr += L1_CACHE_BYTES;
+ }
+
+ write_aux_reg(aux_cmd, vaddr);
+ vaddr += L1_CACHE_BYTES;
+#else
+ write_aux_reg(aux_cmd, paddr);
+ paddr += L1_CACHE_BYTES;
+#endif
+ }
}
-#define OP_INV 0x1
-#define OP_FLUSH 0x2
-#define OP_FLUSH_N_INV 0x3
-
#ifdef CONFIG_ARC_HAS_DCACHE
/***************************************************************
@@ -267,11 +269,9 @@ static inline void wait_for_flush(void)
*/
static inline void __dc_entire_op(const int cacheop)
{
- unsigned long flags, tmp = tmp;
+ unsigned int tmp = tmp;
int aux;
- local_irq_save(flags);
-
if (cacheop == OP_FLUSH_N_INV) {
/* Dcache provides 2 cmd: FLUSH or INV
* INV inturn has sub-modes: DISCARD or FLUSH-BEFORE
@@ -295,58 +295,18 @@ static inline void __dc_entire_op(const int cacheop)
/* Switch back the DISCARD ONLY Invalidate mode */
if (cacheop == OP_FLUSH_N_INV)
write_aux_reg(ARC_REG_DC_CTRL, tmp & ~DC_CTRL_INV_MODE_FLUSH);
-
- local_irq_restore(flags);
}
-/*
- * Per Line Operation on D-Cache
- * Doesn't deal with type-of-op/IRQ-disabling/waiting-for-flush-to-complete
- * It's sole purpose is to help gcc generate ZOL
- */
-static inline void __dc_line_loop(unsigned long start, unsigned long sz,
- int aux_reg)
-{
- int num_lines, slack;
-
- /* Ensure we properly floor/ceil the non-line aligned/sized requests
- * and have @start - aligned to cache line and integral @num_lines.
- * This however can be avoided for page sized since:
- * -@start will be cache-line aligned already (being page aligned)
- * -@sz will be integral multiple of line size (being page sized).
- */
- if (!(__builtin_constant_p(sz) && sz == PAGE_SIZE)) {
- slack = start & ~DCACHE_LINE_MASK;
- sz += slack;
- start -= slack;
- }
-
- num_lines = DIV_ROUND_UP(sz, ARC_DCACHE_LINE_LEN);
-
- while (num_lines-- > 0) {
-#if (CONFIG_ARC_MMU_VER > 2)
- /*
- * Just as for I$, in MMU v3, D$ ops also require
- * "tag" bits in DC_PTAG, "index" bits in FLDL,IVDL ops
- * But we pass phy addr for both. This works since Linux
- * doesn't support aliasing configs for D$, yet.
- * Thus paddr is enough to provide both tag and index.
- */
- write_aux_reg(ARC_REG_DC_PTAG, start);
-#endif
- write_aux_reg(aux_reg, start);
- start += ARC_DCACHE_LINE_LEN;
- }
-}
+/* For kernel mappings cache operation: index is same as paddr */
+#define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op)
/*
* D-Cache : Per Line INV (discard or wback+discard) or FLUSH (wback)
*/
-static inline void __dc_line_op(unsigned long start, unsigned long sz,
- const int cacheop)
+static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr,
+ unsigned long sz, const int cacheop)
{
unsigned long flags, tmp = tmp;
- int aux;
local_irq_save(flags);
@@ -361,12 +321,7 @@ static inline void __dc_line_op(unsigned long start, unsigned long sz,
write_aux_reg(ARC_REG_DC_CTRL, tmp | DC_CTRL_INV_MODE_FLUSH);
}
- if (cacheop & OP_INV) /* Inv / flush-n-inv use same cmd reg */
- aux = ARC_REG_DC_IVDL;
- else
- aux = ARC_REG_DC_FLDL;
-
- __dc_line_loop(start, sz, aux);
+ __cache_line_loop(paddr, vaddr, sz, cacheop);
if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */
wait_for_flush();
@@ -381,7 +336,8 @@ static inline void __dc_line_op(unsigned long start, unsigned long sz,
#else
#define __dc_entire_op(cacheop)
-#define __dc_line_op(start, sz, cacheop)
+#define __dc_line_op(paddr, vaddr, sz, cacheop)
+#define __dc_line_op_k(paddr, sz, cacheop)
#endif /* CONFIG_ARC_HAS_DCACHE */
@@ -391,75 +347,38 @@ static inline void __dc_line_op(unsigned long start, unsigned long sz,
/*
* I-Cache Aliasing in ARC700 VIPT caches
*
- * For fetching code from I$, ARC700 uses vaddr (embedded in program code)
- * to "index" into SET of cache-line and paddr from MMU to match the TAG
- * in the WAYS of SET.
- *
- * However the CDU iterface (to flush/inv) lines from software, only takes
- * paddr (to have simpler hardware interface). For simpler cases, using paddr
- * alone suffices.
- * e.g. 2-way-set-assoc, 16K I$ (8k MMU pg sz, 32b cache line size):
- * way_sz = cache_sz / num_ways = 16k/2 = 8k
- * num_sets = way_sz / line_sz = 8k/32 = 256 => 8 bits
- * Ignoring the bottom 5 bits corresp to the off within a 32b cacheline,
- * bits req for calc set-index = bits 12:5 (0 based). Since this range fits
- * inside the bottom 13 bits of paddr, which are same for vaddr and paddr
- * (with 8k pg sz), paddr alone can be safely used by CDU to unambigously
- * locate a cache-line.
+ * ARC VIPT I-cache uses vaddr to index into cache and paddr to match the tag.
+ * The orig Cache Management Module "CDU" only required paddr to invalidate a
+ * certain line since it sufficed as index in Non-Aliasing VIPT cache-geometry.
+ * Infact for distinct V1,V2,P: all of {V1-P},{V2-P},{P-P} would end up fetching
+ * the exact same line.
*
- * However for a difft sized cache, say 32k I$, above math yields need
- * for 14 bits of vaddr to locate a cache line, which can't be provided by
- * paddr, since the bit 13 (0 based) might differ between the two.
- *
- * This lack of extra bits needed for correct line addressing, defines the
- * classical problem of Cache aliasing with VIPT architectures
- * num_aliases = 1 << extra_bits
- * e.g. 2-way-set-assoc, 32K I$ with 8k MMU pg sz => 2 aliases
- * 2-way-set-assoc, 64K I$ with 8k MMU pg sz => 4 aliases
- * 2-way-set-assoc, 16K I$ with 8k MMU pg sz => NO aliases
+ * However for larger Caches (way-size > page-size) - i.e. in Aliasing config,
+ * paddr alone could not be used to correctly index the cache.
*
* ------------------
* MMU v1/v2 (Fixed Page Size 8k)
* ------------------
* The solution was to provide CDU with these additonal vaddr bits. These
- * would be bits [x:13], x would depend on cache-geom.
+ * would be bits [x:13], x would depend on cache-geometry, 13 comes from
+ * standard page size of 8k.
* H/w folks chose [17:13] to be a future safe range, and moreso these 5 bits
* of vaddr could easily be "stuffed" in the paddr as bits [4:0] since the
* orig 5 bits of paddr were anyways ignored by CDU line ops, as they
* represent the offset within cache-line. The adv of using this "clumsy"
- * interface for additional info was no new reg was needed in CDU.
+ * interface for additional info was no new reg was needed in CDU programming
+ * model.
*
* 17:13 represented the max num of bits passable, actual bits needed were
* fewer, based on the num-of-aliases possible.
* -for 2 alias possibility, only bit 13 needed (32K cache)
* -for 4 alias possibility, bits 14:13 needed (64K cache)
*
- * Since vaddr was not available for all instances of I$ flush req by core
- * kernel, the only safe way (non-optimal though) was to kill all possible
- * lines which could represent an alias (even if they didnt represent one
- * in execution).
- * e.g. for 64K I$, 4 aliases possible, so we did
- * flush start
- * flush start | 0x01
- * flush start | 0x2
- * flush start | 0x3
- *
- * The penalty was invoking the operation itself, since tag match is anyways
- * paddr based, a line which didn't represent an alias would not match the
- * paddr, hence wont be killed
- *
- * Note that aliasing concerns are independent of line-sz for a given cache
- * geometry (size + set_assoc) because the extra bits required by line-sz are
- * reduced from the set calc.
- * e.g. 2-way-set-assoc, 32K I$ with 8k MMU pg sz and using math above
- * 32b line-sz: 9 bits set-index-calc, 5 bits offset-in-line => 1 extra bit
- * 64b line-sz: 8 bits set-index-calc, 6 bits offset-in-line => 1 extra bit
- *
* ------------------
* MMU v3
* ------------------
- * This ver of MMU supports var page sizes (1k-16k) - Linux will support
- * 8k (default), 16k and 4k.
+ * This ver of MMU supports variable page sizes (1k-16k): although Linux will
+ * only support 8k (default), 16k and 4k.
* However from hardware perspective, smaller page sizes aggrevate aliasing
* meaning more vaddr bits needed to disambiguate the cache-line-op ;
* the existing scheme of piggybacking won't work for certain configurations.
@@ -468,144 +387,44 @@ static inline void __dc_line_op(unsigned long start, unsigned long sz,
*/
/***********************************************************
- * Machine specific helpers for per line I-Cache invalidate.
- * 3 routines to accpunt for 1, 2, 4 aliases possible
+ * Machine specific helper for per line I-Cache invalidate.
*/
-
-static void __ic_line_inv_no_alias(unsigned long start, int num_lines)
-{
- while (num_lines-- > 0) {
-#if (CONFIG_ARC_MMU_VER > 2)
- write_aux_reg(ARC_REG_IC_PTAG, start);
-#endif
- write_aux_reg(ARC_REG_IC_IVIL, start);
- start += ARC_ICACHE_LINE_LEN;
- }
-}
-
-static void __ic_line_inv_2_alias(unsigned long start, int num_lines)
-{
- while (num_lines-- > 0) {
-
-#if (CONFIG_ARC_MMU_VER > 2)
- /*
- * MMU v3, CDU prog model (for line ops) now uses a new IC_PTAG
- * reg to pass the "tag" bits and existing IVIL reg only looks
- * at bits relevant for "index" (details above)
- * Programming Notes:
- * -when writing tag to PTAG reg, bit chopping can be avoided,
- * CDU ignores non-tag bits.
- * -Ideally "index" must be computed from vaddr, but it is not
- * avail in these rtns. So to be safe, we kill the lines in all
- * possible indexes corresp to num of aliases possible for
- * given cache config.
- */
- write_aux_reg(ARC_REG_IC_PTAG, start);
- write_aux_reg(ARC_REG_IC_IVIL,
- start & ~(0x1 << PAGE_SHIFT));
- write_aux_reg(ARC_REG_IC_IVIL, start | (0x1 << PAGE_SHIFT));
-#else
- write_aux_reg(ARC_REG_IC_IVIL, start);
- write_aux_reg(ARC_REG_IC_IVIL, start | 0x01);
-#endif
- start += ARC_ICACHE_LINE_LEN;
- }
-}
-
-static void __ic_line_inv_4_alias(unsigned long start, int num_lines)
-{
- while (num_lines-- > 0) {
-
-#if (CONFIG_ARC_MMU_VER > 2)
- write_aux_reg(ARC_REG_IC_PTAG, start);
-
- write_aux_reg(ARC_REG_IC_IVIL,
- start & ~(0x3 << PAGE_SHIFT));
- write_aux_reg(ARC_REG_IC_IVIL,
- start & ~(0x2 << PAGE_SHIFT));
- write_aux_reg(ARC_REG_IC_IVIL,
- start & ~(0x1 << PAGE_SHIFT));
- write_aux_reg(ARC_REG_IC_IVIL, start | (0x3 << PAGE_SHIFT));
-#else
- write_aux_reg(ARC_REG_IC_IVIL, start);
- write_aux_reg(ARC_REG_IC_IVIL, start | 0x01);
- write_aux_reg(ARC_REG_IC_IVIL, start | 0x02);
- write_aux_reg(ARC_REG_IC_IVIL, start | 0x03);
-#endif
- start += ARC_ICACHE_LINE_LEN;
- }
-}
-
-static void __ic_line_inv(unsigned long start, unsigned long sz)
+static void __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr,
+ unsigned long sz)
{
unsigned long flags;
- int num_lines, slack;
-
- /*
- * Ensure we properly floor/ceil the non-line aligned/sized requests
- * and have @start - aligned to cache line, and integral @num_lines
- * However page sized flushes can be compile time optimised.
- * -@start will be cache-line aligned already (being page aligned)
- * -@sz will be integral multiple of line size (being page sized).
- */
- if (!(__builtin_constant_p(sz) && sz == PAGE_SIZE)) {
- slack = start & ~ICACHE_LINE_MASK;
- sz += slack;
- start -= slack;
- }
-
- num_lines = DIV_ROUND_UP(sz, ARC_ICACHE_LINE_LEN);
local_irq_save(flags);
- (*___flush_icache_rtn) (start, num_lines);
+ __cache_line_loop(paddr, vaddr, sz, OP_INV_IC);
local_irq_restore(flags);
}
-/* Unlike routines above, having vaddr for flush op (along with paddr),
- * prevents the need to speculatively kill the lines in multiple sets
- * based on ratio of way_sz : pg_sz
- */
-static void __ic_line_inv_vaddr(unsigned long phy_start,
- unsigned long vaddr, unsigned long sz)
+static inline void __ic_entire_inv(void)
{
- unsigned long flags;
- int num_lines, slack;
- unsigned int addr;
-
- slack = phy_start & ~ICACHE_LINE_MASK;
- sz += slack;
- phy_start -= slack;
- num_lines = DIV_ROUND_UP(sz, ARC_ICACHE_LINE_LEN);
-
-#if (CONFIG_ARC_MMU_VER > 2)
- vaddr &= ~ICACHE_LINE_MASK;
- addr = phy_start;
-#else
- /* bits 17:13 of vaddr go as bits 4:0 of paddr */
- addr = phy_start | ((vaddr >> 13) & 0x1F);
-#endif
+ write_aux_reg(ARC_REG_IC_IVIC, 1);
+ read_aux_reg(ARC_REG_IC_CTRL); /* blocks */
+}
- local_irq_save(flags);
- while (num_lines-- > 0) {
-#if (CONFIG_ARC_MMU_VER > 2)
- /* tag comes from phy addr */
- write_aux_reg(ARC_REG_IC_PTAG, addr);
+struct ic_line_inv_vaddr_ipi {
+ unsigned long paddr, vaddr;
+ int sz;
+};
- /* index bits come from vaddr */
- write_aux_reg(ARC_REG_IC_IVIL, vaddr);
- vaddr += ARC_ICACHE_LINE_LEN;
-#else
- /* this paddr contains vaddrs bits as needed */
- write_aux_reg(ARC_REG_IC_IVIL, addr);
-#endif
- addr += ARC_ICACHE_LINE_LEN;
- }
- local_irq_restore(flags);
+static void __ic_line_inv_vaddr_helper(void *info)
+{
+ struct ic_line_inv_vaddr_ipi *ic_inv = (struct ic_line_inv_vaddr_ipi*) info;
+ __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz);
}
+static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr,
+ unsigned long sz)
+{
+ struct ic_line_inv_vaddr_ipi ic_inv = { paddr, vaddr , sz};
+ on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1);
+}
#else
-#define __ic_line_inv(start, sz)
+#define __ic_entire_inv()
#define __ic_line_inv_vaddr(pstart, vstart, sz)
#endif /* CONFIG_ARC_HAS_ICACHE */
@@ -615,35 +434,72 @@ static void __ic_line_inv_vaddr(unsigned long phy_start,
* Exported APIs
*/
-/* TBD: use pg_arch_1 to optimize this */
+/*
+ * Handle cache congruency of kernel and userspace mappings of page when kernel
+ * writes-to/reads-from
+ *
+ * The idea is to defer flushing of kernel mapping after a WRITE, possible if:
+ * -dcache is NOT aliasing, hence any U/K-mappings of page are congruent
+ * -U-mapping doesn't exist yet for page (finalised in update_mmu_cache)
+ * -In SMP, if hardware caches are coherent
+ *
+ * There's a corollary case, where kernel READs from a userspace mapped page.
+ * If the U-mapping is not congruent to to K-mapping, former needs flushing.
+ */
void flush_dcache_page(struct page *page)
{
- __dc_line_op((unsigned long)page_address(page), PAGE_SIZE, OP_FLUSH);
+ struct address_space *mapping;
+
+ if (!cache_is_vipt_aliasing()) {
+ clear_bit(PG_dc_clean, &page->flags);
+ return;
+ }
+
+ /* don't handle anon pages here */
+ mapping = page_mapping(page);
+ if (!mapping)
+ return;
+
+ /*
+ * pagecache page, file not yet mapped to userspace
+ * Make a note that K-mapping is dirty
+ */
+ if (!mapping_mapped(mapping)) {
+ clear_bit(PG_dc_clean, &page->flags);
+ } else if (page_mapped(page)) {
+
+ /* kernel reading from page with U-mapping */
+ void *paddr = page_address(page);
+ unsigned long vaddr = page->index << PAGE_CACHE_SHIFT;
+
+ if (addr_not_cache_congruent(paddr, vaddr))
+ __flush_dcache_page(paddr, vaddr);
+ }
}
EXPORT_SYMBOL(flush_dcache_page);
void dma_cache_wback_inv(unsigned long start, unsigned long sz)
{
- __dc_line_op(start, sz, OP_FLUSH_N_INV);
+ __dc_line_op_k(start, sz, OP_FLUSH_N_INV);
}
EXPORT_SYMBOL(dma_cache_wback_inv);
void dma_cache_inv(unsigned long start, unsigned long sz)
{
- __dc_line_op(start, sz, OP_INV);
+ __dc_line_op_k(start, sz, OP_INV);
}
EXPORT_SYMBOL(dma_cache_inv);
void dma_cache_wback(unsigned long start, unsigned long sz)
{
- __dc_line_op(start, sz, OP_FLUSH);
+ __dc_line_op_k(start, sz, OP_FLUSH);
}
EXPORT_SYMBOL(dma_cache_wback);
/*
- * This is API for making I/D Caches consistent when modifying code
- * (loadable modules, kprobes, etc)
+ * This is API for making I/D Caches consistent when modifying
+ * kernel code (loadable modules, kprobes, kgdb...)
* This is called on insmod, with kernel virtual address for CODE of
* the module. ARC cache maintenance ops require PHY address thus we
* need to convert vmalloc addr to PHY addr
@@ -652,7 +508,6 @@ void flush_icache_range(unsigned long kstart, unsigned long kend)
{
unsigned int tot_sz, off, sz;
unsigned long phy, pfn;
- unsigned long flags;
/* printk("Kernel Cache Cohenercy: %lx to %lx\n",kstart, kend); */
@@ -673,8 +528,13 @@ void flush_icache_range(unsigned long kstart, unsigned long kend)
/* Case: Kernel Phy addr (0x8000_0000 onwards) */
if (likely(kstart > PAGE_OFFSET)) {
- __ic_line_inv(kstart, kend - kstart);
- __dc_line_op(kstart, kend - kstart, OP_FLUSH);
+ /*
+ * The 2nd arg despite being paddr will be used to index icache
+ * This is OK since no alternate virtual mappings will exist
+ * given the callers for this case: kprobe/kgdb in built-in
+ * kernel code only.
+ */
+ __sync_icache_dcache(kstart, kstart, kend - kstart);
return;
}
@@ -692,70 +552,144 @@ void flush_icache_range(unsigned long kstart, unsigned long kend)
pfn = vmalloc_to_pfn((void *)kstart);
phy = (pfn << PAGE_SHIFT) + off;
sz = min_t(unsigned int, tot_sz, PAGE_SIZE - off);
- local_irq_save(flags);
- __dc_line_op(phy, sz, OP_FLUSH);
- __ic_line_inv(phy, sz);
- local_irq_restore(flags);
+ __sync_icache_dcache(phy, kstart, sz);
kstart += sz;
tot_sz -= sz;
}
}
/*
- * Optimised ver of flush_icache_range() with spec callers: ptrace/signals
- * where vaddr is also available. This allows passing both vaddr and paddr
- * bits to CDU for cache flush, short-circuting the current pessimistic algo
- * which kills all possible aliases.
- * An added adv of knowing that vaddr is user-vaddr avoids various checks
- * and handling for k-vaddr, k-paddr as done in orig ver above
+ * General purpose helper to make I and D cache lines consistent.
+ * @paddr is phy addr of region
+ * @vaddr is typically user vaddr (breakpoint) or kernel vaddr (vmalloc)
+ * However in one instance, when called by kprobe (for a breakpt in
+ * builtin kernel code) @vaddr will be paddr only, meaning CDU operation will
+ * use a paddr to index the cache (despite VIPT). This is fine since since a
+ * builtin kernel page will not have any virtual mappings.
+ * kprobe on loadable module will be kernel vaddr.
*/
-void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
- int len)
+void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len)
{
- __ic_line_inv_vaddr(paddr, u_vaddr, len);
- __dc_line_op(paddr, len, OP_FLUSH);
+ __dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV);
+ __ic_line_inv_vaddr(paddr, vaddr, len);
+}
+
+/* wrapper to compile time eliminate alignment checks in flush loop */
+void __inv_icache_page(unsigned long paddr, unsigned long vaddr)
+{
+ __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE);
}
/*
- * XXX: This also needs to be optim using pg_arch_1
- * This is called when a page-cache page is about to be mapped into a
- * user process' address space. It offers an opportunity for a
- * port to ensure d-cache/i-cache coherency if necessary.
+ * wrapper to clearout kernel or userspace mappings of a page
+ * For kernel mappings @vaddr == @paddr
*/
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+void ___flush_dcache_page(unsigned long paddr, unsigned long vaddr)
{
- if (!(vma->vm_flags & VM_EXEC))
- return;
-
- __ic_line_inv((unsigned long)page_address(page), PAGE_SIZE);
+ __dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV);
}
-void flush_icache_all(void)
+noinline void flush_cache_all(void)
{
unsigned long flags;
local_irq_save(flags);
- write_aux_reg(ARC_REG_IC_IVIC, 1);
+ __ic_entire_inv();
+ __dc_entire_op(OP_FLUSH_N_INV);
- /* lr will not complete till the icache inv operation is not over */
- read_aux_reg(ARC_REG_IC_CTRL);
local_irq_restore(flags);
+
}
-noinline void flush_cache_all(void)
+#ifdef CONFIG_ARC_CACHE_VIPT_ALIASING
+
+void flush_cache_mm(struct mm_struct *mm)
{
- unsigned long flags;
+ flush_cache_all();
+}
- local_irq_save(flags);
+void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr,
+ unsigned long pfn)
+{
+ unsigned int paddr = pfn << PAGE_SHIFT;
- flush_icache_all();
- __dc_entire_op(OP_FLUSH_N_INV);
+ u_vaddr &= PAGE_MASK;
- local_irq_restore(flags);
+ ___flush_dcache_page(paddr, u_vaddr);
+
+ if (vma->vm_flags & VM_EXEC)
+ __inv_icache_page(paddr, u_vaddr);
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ flush_cache_all();
+}
+
+void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long u_vaddr)
+{
+ /* TBD: do we really need to clear the kernel mapping */
+ __flush_dcache_page(page_address(page), u_vaddr);
+ __flush_dcache_page(page_address(page), page_address(page));
}
+#endif
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long u_vaddr, struct vm_area_struct *vma)
+{
+ void *kfrom = page_address(from);
+ void *kto = page_address(to);
+ int clean_src_k_mappings = 0;
+
+ /*
+ * If SRC page was already mapped in userspace AND it's U-mapping is
+ * not congruent with K-mapping, sync former to physical page so that
+ * K-mapping in memcpy below, sees the right data
+ *
+ * Note that while @u_vaddr refers to DST page's userspace vaddr, it is
+ * equally valid for SRC page as well
+ */
+ if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
+ __flush_dcache_page(kfrom, u_vaddr);
+ clean_src_k_mappings = 1;
+ }
+
+ copy_page(kto, kfrom);
+
+ /*
+ * Mark DST page K-mapping as dirty for a later finalization by
+ * update_mmu_cache(). Although the finalization could have been done
+ * here as well (given that both vaddr/paddr are available).
+ * But update_mmu_cache() already has code to do that for other
+ * non copied user pages (e.g. read faults which wire in pagecache page
+ * directly).
+ */
+ clear_bit(PG_dc_clean, &to->flags);
+
+ /*
+ * if SRC was already usermapped and non-congruent to kernel mapping
+ * sync the kernel mapping back to physical page
+ */
+ if (clean_src_k_mappings) {
+ __flush_dcache_page(kfrom, kfrom);
+ set_bit(PG_dc_clean, &from->flags);
+ } else {
+ clear_bit(PG_dc_clean, &from->flags);
+ }
+}
+
+void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
+{
+ clear_page(to);
+ clear_bit(PG_dc_clean, &page->flags);
+}
+
+
/**********************************************************************
* Explicit Cache flush request from user space via syscall
* Needed for JITs which generate code on the fly
diff --git a/arch/arc/mm/extable.c b/arch/arc/mm/extable.c
index 014172ba843..aa652e28132 100644
--- a/arch/arc/mm/extable.c
+++ b/arch/arc/mm/extable.c
@@ -27,7 +27,7 @@ int fixup_exception(struct pt_regs *regs)
#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-long arc_copy_from_user_noinline(void *to, const void __user * from,
+long arc_copy_from_user_noinline(void *to, const void __user *from,
unsigned long n)
{
return __arc_copy_from_user(to, from, n);
@@ -48,7 +48,7 @@ unsigned long arc_clear_user_noinline(void __user *to,
}
EXPORT_SYMBOL(arc_clear_user_noinline);
-long arc_strncpy_from_user_noinline (char *dst, const char __user *src,
+long arc_strncpy_from_user_noinline(char *dst, const char __user *src,
long count)
{
return __arc_strncpy_from_user(dst, src, count);
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index af55aab803d..9c69552350c 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -12,12 +12,12 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
-#include <linux/version.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <asm/pgalloc.h>
+#include <asm/mmu.h>
-static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
+static int handle_vmalloc_fault(unsigned long address)
{
/*
* Synchronize this task's top level page-table
@@ -27,7 +27,7 @@ static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;
- pgd = pgd_offset_fast(mm, address);
+ pgd = pgd_offset_fast(current->active_mm, address);
pgd_k = pgd_offset_k(address);
if (!pgd_present(*pgd_k))
@@ -52,16 +52,15 @@ bad_area:
return 1;
}
-void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
- unsigned long cause_code)
+void do_page_fault(unsigned long address, struct pt_regs *regs)
{
struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
siginfo_t info;
int fault, ret;
- unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
- (write ? FAULT_FLAG_WRITE : 0);
+ int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
/*
* We fault-in kernel-space virtual memory on-demand. The
@@ -73,7 +72,7 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
* nothing more.
*/
if (address >= VMALLOC_START && address <= VMALLOC_END) {
- ret = handle_vmalloc_fault(mm, address);
+ ret = handle_vmalloc_fault(address);
if (unlikely(ret))
goto bad_area_nosemaphore;
else
@@ -89,6 +88,8 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
if (in_atomic() || !mm)
goto no_context;
+ if (user_mode(regs))
+ flags |= FAULT_FLAG_USER;
retry:
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -110,18 +111,19 @@ good_area:
/* Handle protection violation, execute on heap or stack */
- if (cause_code == ((ECR_V_PROTV << 16) | ECR_C_PROTV_INST_FETCH))
+ if ((regs->ecr_vec == ECR_V_PROTV) &&
+ (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
goto bad_area;
if (write) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
+ flags |= FAULT_FLAG_WRITE;
} else {
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
-survive:
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
@@ -177,7 +179,6 @@ bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) {
tsk->thread.fault_address = address;
- tsk->thread.cause_code = cause_code;
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code has been set above */
@@ -198,17 +199,15 @@ no_context:
if (fixup_exception(regs))
return;
- die("Oops", regs, address, cause_code);
+ die("Oops", regs, address);
out_of_memory:
- if (is_global_init(tsk)) {
- yield();
- goto survive;
- }
up_read(&mm->mmap_sem);
- if (user_mode(regs))
- do_group_exit(SIGKILL); /* This will never return */
+ if (user_mode(regs)) {
+ pagefault_out_of_memory();
+ return;
+ }
goto no_context;
@@ -219,7 +218,6 @@ do_sigbus:
goto no_context;
tsk->thread.fault_address = address;
- tsk->thread.cause_code = cause_code;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c
index caf797de23f..523412369f7 100644
--- a/arch/arc/mm/init.c
+++ b/arch/arc/mm/init.c
@@ -10,8 +10,8 @@
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
-#ifdef CONFIG_BLOCK_DEV_RAM
-#include <linux/blk.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/initrd.h>
#endif
#include <linux/swap.h>
#include <linux/module.h>
@@ -45,6 +45,24 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
pr_info("Memory size set via devicetree %ldM\n", TO_MB(arc_mem_sz));
}
+#ifdef CONFIG_BLK_DEV_INITRD
+static int __init early_initrd(char *p)
+{
+ unsigned long start, size;
+ char *endp;
+
+ start = memparse(p, &endp);
+ if (*endp == ',') {
+ size = memparse(endp + 1, NULL);
+
+ initrd_start = (unsigned long)__va(start);
+ initrd_end = (unsigned long)__va(start + size);
+ }
+ return 0;
+}
+early_param("initrd", early_initrd);
+#endif
+
/*
* First memory setup routine called from setup_arch()
* 1. setup swapper's mm @init_mm
@@ -77,17 +95,23 @@ void __init setup_arch_memory(void)
/* Last usable page of low mem (no HIGHMEM yet for ARC port) */
max_low_pfn = max_pfn = PFN_DOWN(end_mem);
- max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
+ max_mapnr = max_low_pfn - min_low_pfn;
/*------------- reserve kernel image -----------------------*/
memblock_reserve(CONFIG_LINUX_LINK_BASE,
__pa(_end) - CONFIG_LINUX_LINK_BASE);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /*------------- reserve initrd image -----------------------*/
+ if (initrd_start)
+ memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif
+
memblock_dump_all();
/*-------------- node setup --------------------------------*/
memset(zones_size, 0, sizeof(zones_size));
- zones_size[ZONE_NORMAL] = num_physpages;
+ zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
/*
* We can't use the helper free_area_init(zones[]) because it uses
@@ -109,56 +133,9 @@ void __init setup_arch_memory(void)
*/
void __init mem_init(void)
{
- int codesize, datasize, initsize, reserved_pages, free_pages;
- int tmp;
-
high_memory = (void *)(CONFIG_LINUX_LINK_BASE + arc_mem_sz);
-
- totalram_pages = free_all_bootmem();
-
- /* count all reserved pages [kernel code/data/mem_map..] */
- reserved_pages = 0;
- for (tmp = 0; tmp < max_mapnr; tmp++)
- if (PageReserved(mem_map + tmp))
- reserved_pages++;
-
- /* XXX: nr_free_pages() is equivalent */
- free_pages = max_mapnr - reserved_pages;
-
- /*
- * For the purpose of display below, split the "reserve mem"
- * kernel code/data is already shown explicitly,
- * Show any other reservations (mem_map[ ] et al)
- */
- reserved_pages -= (((unsigned int)_end - CONFIG_LINUX_LINK_BASE) >>
- PAGE_SHIFT);
-
- codesize = _etext - _text;
- datasize = _end - _etext;
- initsize = __init_end - __init_begin;
-
- pr_info("Memory Available: %dM / %ldM (%dK code, %dK data, %dK init, %dK reserv)\n",
- PAGES_TO_MB(free_pages),
- TO_MB(arc_mem_sz),
- TO_KB(codesize), TO_KB(datasize), TO_KB(initsize),
- PAGES_TO_KB(reserved_pages));
-}
-
-static void __init free_init_pages(const char *what, unsigned long begin,
- unsigned long end)
-{
- unsigned long addr;
-
- pr_info("Freeing %s: %ldk [%lx] to [%lx]\n",
- what, TO_KB(end - begin), begin, end);
-
- /* need to check that the page we free is not a partial page */
- for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
/*
@@ -166,22 +143,12 @@ static void __init free_init_pages(const char *what, unsigned long begin,
*/
void __init_refok free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)__init_begin,
- (unsigned long)__init_end);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory", start, end);
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
-
-#ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
- unsigned long end)
-{
- pr_err("%s(%lx, %lx)\n", __func__, start, end);
-}
-#endif /* CONFIG_OF_FLATTREE */
diff --git a/arch/arc/mm/ioremap.c b/arch/arc/mm/ioremap.c
index 3e5c92c7993..739e65f355d 100644
--- a/arch/arc/mm/ioremap.c
+++ b/arch/arc/mm/ioremap.c
@@ -12,7 +12,7 @@
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <asm/cache.h>
+#include <linux/cache.h>
void __iomem *ioremap(unsigned long paddr, unsigned long size)
{
diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c
new file mode 100644
index 00000000000..2e06d56e987
--- /dev/null
+++ b/arch/arc/mm/mmap.c
@@ -0,0 +1,78 @@
+/*
+ * ARC700 mmap
+ *
+ * (started from arm version - for VIPT alias handling)
+ *
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <asm/cacheflush.h>
+
+#define COLOUR_ALIGN(addr, pgoff) \
+ ((((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) + \
+ (((pgoff) << PAGE_SHIFT) & (SHMLBA - 1)))
+
+/*
+ * Ensure that shared mappings are correctly aligned to
+ * avoid aliasing issues with VIPT caches.
+ * We need to ensure that
+ * a specific page of an object is always mapped at a multiple of
+ * SHMLBA bytes.
+ */
+unsigned long
+arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int do_align = 0;
+ int aliasing = cache_is_vipt_aliasing();
+ struct vm_unmapped_area_info info;
+
+ /*
+ * We only need to do colour alignment if D cache aliases.
+ */
+ if (aliasing)
+ do_align = filp || (flags & MAP_SHARED);
+
+ /*
+ * We enforce the MAP_FIXED case.
+ */
+ if (flags & MAP_FIXED) {
+ if (aliasing && flags & MAP_SHARED &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
+ return addr;
+ }
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (addr) {
+ if (do_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = mm->mmap_base;
+ info.high_limit = TASK_SIZE;
+ info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
+ info.align_offset = pgoff << PAGE_SHIFT;
+ return vm_unmapped_area(&info);
+}
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index 9b9ce23f4ec..e1acf0ce564 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -52,10 +52,11 @@
*/
#include <linux/module.h>
+#include <linux/bug.h>
#include <asm/arcregs.h>
#include <asm/setup.h>
#include <asm/mmu_context.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
/* Need for ARC MMU v2
*
@@ -97,49 +98,47 @@
* J-TLB entry got evicted/replaced.
*/
-/* A copy of the ASID from the PID reg is kept in asid_cache */
-int asid_cache = FIRST_ASID;
-/* ASID to mm struct mapping. We have one extra entry corresponding to
- * NO_ASID to save us a compare when clearing the mm entry for old asid
- * see get_new_mmu_context (asm-arc/mmu_context.h)
- */
-struct mm_struct *asid_mm_map[NUM_ASID + 1];
+/* A copy of the ASID from the PID reg is kept in asid_cache */
+DEFINE_PER_CPU(unsigned int, asid_cache) = MM_CTXT_FIRST_CYCLE;
/*
* Utility Routine to erase a J-TLB entry
- * The procedure is to look it up in the MMU. If found, ERASE it by
- * issuing a TlbWrite CMD with PD0 = PD1 = 0
+ * Caller needs to setup Index Reg (manually or via getIndex)
*/
-
-static void __tlb_entry_erase(void)
+static inline void __tlb_entry_erase(void)
{
write_aux_reg(ARC_REG_TLBPD1, 0);
write_aux_reg(ARC_REG_TLBPD0, 0);
write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
}
-static void tlb_entry_erase(unsigned int vaddr_n_asid)
+static inline unsigned int tlb_entry_lkup(unsigned long vaddr_n_asid)
{
unsigned int idx;
- /* Locate the TLB entry for this vaddr + ASID */
write_aux_reg(ARC_REG_TLBPD0, vaddr_n_asid);
+
write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
idx = read_aux_reg(ARC_REG_TLBINDEX);
+ return idx;
+}
+
+static void tlb_entry_erase(unsigned int vaddr_n_asid)
+{
+ unsigned int idx;
+
+ /* Locate the TLB entry for this vaddr + ASID */
+ idx = tlb_entry_lkup(vaddr_n_asid);
+
/* No error means entry found, zero it out */
if (likely(!(idx & TLB_LKUP_ERR))) {
__tlb_entry_erase();
- } else { /* Some sort of Error */
-
+ } else {
/* Duplicate entry error */
- if (idx & 0x1) {
- /* TODO we need to handle this case too */
- pr_emerg("unhandled Duplicate flush for %x\n",
- vaddr_n_asid);
- }
- /* else entry not found so nothing to do */
+ WARN(idx == TLB_DUP_ERR, "Probe returned Dup PD for %x\n",
+ vaddr_n_asid);
}
}
@@ -158,7 +157,7 @@ static void utlb_invalidate(void)
{
#if (CONFIG_ARC_MMU_VER >= 2)
-#if (CONFIG_ARC_MMU_VER < 3)
+#if (CONFIG_ARC_MMU_VER == 2)
/* MMU v2 introduced the uTLB Flush command.
* There was however an obscure hardware bug, where uTLB flush would
* fail when a prior probe for J-TLB (both totally unrelated) would
@@ -181,6 +180,36 @@ static void utlb_invalidate(void)
}
+static void tlb_entry_insert(unsigned int pd0, unsigned int pd1)
+{
+ unsigned int idx;
+
+ /*
+ * First verify if entry for this vaddr+ASID already exists
+ * This also sets up PD0 (vaddr, ASID..) for final commit
+ */
+ idx = tlb_entry_lkup(pd0);
+
+ /*
+ * If Not already present get a free slot from MMU.
+ * Otherwise, Probe would have located the entry and set INDEX Reg
+ * with existing location. This will cause Write CMD to over-write
+ * existing entry with new PD0 and PD1
+ */
+ if (likely(idx & TLB_LKUP_ERR))
+ write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+
+ /* setup the other half of TLB entry (pfn, rwx..) */
+ write_aux_reg(ARC_REG_TLBPD1, pd1);
+
+ /*
+ * Commit the Entry to MMU
+ * It doesnt sound safe to use the TLBWriteNI cmd here
+ * which doesn't flush uTLBs. I'd rather be safe than sorry.
+ */
+ write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+}
+
/*
* Un-conditionally (without lookup) erase the entire MMU contents
*/
@@ -223,13 +252,14 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
return;
/*
- * Workaround for Android weirdism:
- * A binder VMA could end up in a task such that vma->mm != tsk->mm
- * old code would cause h/w - s/w ASID to get out of sync
+ * - Move to a new ASID, but only if the mm is still wired in
+ * (Android Binder ended up calling this for vma->mm != tsk->mm,
+ * causing h/w - s/w ASID to get out of sync)
+ * - Also get_new_mmu_context() new implementation allocates a new
+ * ASID only if it is not allocated already - so unallocate first
*/
- if (current->mm != mm)
- destroy_context(mm);
- else
+ destroy_context(mm);
+ if (current->mm == mm)
get_new_mmu_context(mm);
}
@@ -244,8 +274,8 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
+ const unsigned int cpu = smp_processor_id();
unsigned long flags;
- unsigned int asid;
/* If range @start to @end is more than 32 TLB entries deep,
* its better to move to a new ASID rather than searching for
@@ -267,11 +297,10 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
start &= PAGE_MASK;
local_irq_save(flags);
- asid = vma->vm_mm->context.asid;
- if (asid != NO_ASID) {
+ if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) {
while (start < end) {
- tlb_entry_erase(start | (asid & 0xff));
+ tlb_entry_erase(start | hw_pid(vma->vm_mm, cpu));
start += PAGE_SIZE;
}
}
@@ -318,6 +347,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
+ const unsigned int cpu = smp_processor_id();
unsigned long flags;
/* Note that it is critical that interrupts are DISABLED between
@@ -325,23 +355,95 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
*/
local_irq_save(flags);
- if (vma->vm_mm->context.asid != NO_ASID) {
- tlb_entry_erase((page & PAGE_MASK) |
- (vma->vm_mm->context.asid & 0xff));
+ if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) {
+ tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm, cpu));
utlb_invalidate();
}
local_irq_restore(flags);
}
+#ifdef CONFIG_SMP
+
+struct tlb_args {
+ struct vm_area_struct *ta_vma;
+ unsigned long ta_start;
+ unsigned long ta_end;
+};
+
+static inline void ipi_flush_tlb_page(void *arg)
+{
+ struct tlb_args *ta = arg;
+
+ local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_range(void *arg)
+{
+ struct tlb_args *ta = arg;
+
+ local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+}
+
+static inline void ipi_flush_tlb_kernel_range(void *arg)
+{
+ struct tlb_args *ta = (struct tlb_args *)arg;
+
+ local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
+}
+
+void flush_tlb_all(void)
+{
+ on_each_cpu((smp_call_func_t)local_flush_tlb_all, NULL, 1);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ on_each_cpu_mask(mm_cpumask(mm), (smp_call_func_t)local_flush_tlb_mm,
+ mm, 1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+ struct tlb_args ta = {
+ .ta_vma = vma,
+ .ta_start = uaddr
+ };
+
+ on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page, &ta, 1);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ struct tlb_args ta = {
+ .ta_vma = vma,
+ .ta_start = start,
+ .ta_end = end
+ };
+
+ on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range, &ta, 1);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ struct tlb_args ta = {
+ .ta_start = start,
+ .ta_end = end
+ };
+
+ on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+}
+#endif
+
/*
* Routine to create a TLB entry
*/
void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
{
unsigned long flags;
- unsigned int idx, asid_or_sasid;
- unsigned long pd0_flags;
+ unsigned int asid_or_sasid, rwx;
+ unsigned long pd0, pd1;
/*
* create_tlb() assumes that current->mm == vma->mm, since
@@ -373,73 +475,112 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
local_irq_save(flags);
- tlb_paranoid_check(vma->vm_mm->context.asid, address);
+ tlb_paranoid_check(asid_mm(vma->vm_mm, smp_processor_id()), address);
address &= PAGE_MASK;
/* update this PTE credentials */
pte_val(*ptep) |= (_PAGE_PRESENT | _PAGE_ACCESSED);
- /* Create HW TLB entry Flags (in PD0) from PTE Flags */
-#if (CONFIG_ARC_MMU_VER <= 2)
- pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0) >> 1);
-#else
- pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0));
-#endif
+ /* Create HW TLB(PD0,PD1) from PTE */
/* ASID for this task */
asid_or_sasid = read_aux_reg(ARC_REG_PID) & 0xff;
- write_aux_reg(ARC_REG_TLBPD0, address | pd0_flags | asid_or_sasid);
-
- /* Load remaining info in PD1 (Page Frame Addr and Kx/Kw/Kr Flags) */
- write_aux_reg(ARC_REG_TLBPD1, (pte_val(*ptep) & PTE_BITS_IN_PD1));
-
- /* First verify if entry for this vaddr+ASID already exists */
- write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
- idx = read_aux_reg(ARC_REG_TLBINDEX);
+ pd0 = address | asid_or_sasid | (pte_val(*ptep) & PTE_BITS_IN_PD0);
/*
- * If Not already present get a free slot from MMU.
- * Otherwise, Probe would have located the entry and set INDEX Reg
- * with existing location. This will cause Write CMD to over-write
- * existing entry with new PD0 and PD1
+ * ARC MMU provides fully orthogonal access bits for K/U mode,
+ * however Linux only saves 1 set to save PTE real-estate
+ * Here we convert 3 PTE bits into 6 MMU bits:
+ * -Kernel only entries have Kr Kw Kx 0 0 0
+ * -User entries have mirrored K and U bits
*/
- if (likely(idx & TLB_LKUP_ERR))
- write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+ rwx = pte_val(*ptep) & PTE_BITS_RWX;
- /*
- * Commit the Entry to MMU
- * It doesnt sound safe to use the TLBWriteNI cmd here
- * which doesn't flush uTLBs. I'd rather be safe than sorry.
- */
- write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+ if (pte_val(*ptep) & _PAGE_GLOBAL)
+ rwx <<= 3; /* r w x => Kr Kw Kx 0 0 0 */
+ else
+ rwx |= (rwx << 3); /* r w x => Kr Kw Kx Ur Uw Ux */
+
+ pd1 = rwx | (pte_val(*ptep) & PTE_BITS_NON_RWX_IN_PD1);
+
+ tlb_entry_insert(pd0, pd1);
local_irq_restore(flags);
}
-/* arch hook called by core VM at the end of handle_mm_fault( ),
- * when a new PTE is entered in Page Tables or an existing one
- * is modified. We aggresively pre-install a TLB entry
+/*
+ * Called at the end of pagefault, for a userspace mapped page
+ * -pre-install the corresponding TLB entry into MMU
+ * -Finalize the delayed D-cache flush of kernel mapping of page due to
+ * flush_dcache_page(), copy_user_page()
+ *
+ * Note that flush (when done) involves both WBACK - so physical page is
+ * in sync as well as INV - so any non-congruent aliases don't remain
*/
-
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddress,
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
pte_t *ptep)
{
+ unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
+ unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
+ struct page *page = pfn_to_page(pte_pfn(*ptep));
+
+ create_tlb(vma, vaddr, ptep);
- create_tlb(vma, vaddress, ptep);
+ if (page == ZERO_PAGE(0)) {
+ return;
+ }
+
+ /*
+ * Exec page : Independent of aliasing/page-color considerations,
+ * since icache doesn't snoop dcache on ARC, any dirty
+ * K-mapping of a code page needs to be wback+inv so that
+ * icache fetch by userspace sees code correctly.
+ * !EXEC page: If K-mapping is NOT congruent to U-mapping, flush it
+ * so userspace sees the right data.
+ * (Avoids the flush for Non-exec + congruent mapping case)
+ */
+ if ((vma->vm_flags & VM_EXEC) ||
+ addr_not_cache_congruent(paddr, vaddr)) {
+
+ int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
+ if (dirty) {
+ /* wback + inv dcache lines */
+ __flush_dcache_page(paddr, paddr);
+
+ /* invalidate any existing icache lines */
+ if (vma->vm_flags & VM_EXEC)
+ __inv_icache_page(paddr, vaddr);
+ }
+ }
}
/* Read the Cache Build Confuration Registers, Decode them and save into
* the cpuinfo structure for later use.
* No Validation is done here, simply read/convert the BCRs
*/
-void __init read_decode_mmu_bcr(void)
+void read_decode_mmu_bcr(void)
{
- unsigned int tmp;
- struct bcr_mmu_1_2 *mmu2; /* encoded MMU2 attr */
- struct bcr_mmu_3 *mmu3; /* encoded MMU3 attr */
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+ unsigned int tmp;
+ struct bcr_mmu_1_2 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
+#else
+ unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
+#endif
+ } *mmu2;
+
+ struct bcr_mmu_3 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
+ u_itlb:4, u_dtlb:4;
+#else
+ unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
+ ways:4, ver:8;
+#endif
+ } *mmu3;
tmp = read_aux_reg(ARC_REG_MMU_BCR);
mmu->ver = (tmp >> 24);
@@ -466,7 +607,7 @@ void __init read_decode_mmu_bcr(void)
char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
{
int n = 0;
- struct cpuinfo_arc_mmu *p_mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+ struct cpuinfo_arc_mmu *p_mmu = &cpuinfo_arc700[cpu_id].mmu;
n += scnprintf(buf + n, len - n, "ARC700 MMU [v%x]\t: %dk PAGE, ",
p_mmu->ver, TO_KB(p_mmu->pg_sz));
@@ -475,12 +616,12 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
"J-TLB %d (%dx%d), uDTLB %d, uITLB %d, %s\n",
p_mmu->num_tlb, p_mmu->sets, p_mmu->ways,
p_mmu->u_dtlb, p_mmu->u_itlb,
- __CONFIG_ARC_MMU_SASID_VAL ? "SASID" : "");
+ IS_ENABLED(CONFIG_ARC_MMU_SASID) ? "SASID" : "");
return buf;
}
-void __init arc_mmu_init(void)
+void arc_mmu_init(void)
{
char str[256];
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
@@ -503,13 +644,6 @@ void __init arc_mmu_init(void)
if (mmu->pg_sz != PAGE_SIZE)
panic("MMU pg size != PAGE_SIZE (%luk)\n", TO_KB(PAGE_SIZE));
- /*
- * ASID mgmt data structures are compile time init
- * asid_cache = FIRST_ASID and asid_mm_map[] all zeroes
- */
-
- local_flush_tlb_all();
-
/* Enable the MMU */
write_aux_reg(ARC_REG_PID, MMU_ENABLE);
@@ -551,9 +685,9 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
struct pt_regs *regs)
{
int set, way, n;
- unsigned int pd0[4], pd1[4]; /* assume max 4 ways */
unsigned long flags, is_valid;
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+ unsigned int pd0[mmu->ways], pd1[mmu->ways];
local_irq_save(flags);
@@ -578,7 +712,7 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
continue;
/* Scan the set for duplicate ways: needs a nested loop */
- for (way = 0; way < mmu->ways; way++) {
+ for (way = 0; way < mmu->ways - 1; way++) {
if (!pd0[way])
continue;
@@ -621,25 +755,28 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
* Low Level ASM TLB handler calls this if it finds that HW and SW ASIDS
* don't match
*/
-void print_asid_mismatch(int is_fast_path)
+void print_asid_mismatch(int mm_asid, int mmu_asid, int is_fast_path)
{
- int pid_sw, pid_hw;
- pid_sw = current->active_mm->context.asid;
- pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
-
pr_emerg("ASID Mismatch in %s Path Handler: sw-pid=0x%x hw-pid=0x%x\n",
- is_fast_path ? "Fast" : "Slow", pid_sw, pid_hw);
+ is_fast_path ? "Fast" : "Slow", mm_asid, mmu_asid);
__asm__ __volatile__("flag 1");
}
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long addr)
+void tlb_paranoid_check(unsigned int mm_asid, unsigned long addr)
{
- unsigned int pid_hw;
+ unsigned int mmu_asid;
- pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
+ mmu_asid = read_aux_reg(ARC_REG_PID) & 0xff;
- if (addr < 0x70000000 && ((pid_hw != pid_sw) || (pid_sw == NO_ASID)))
- print_asid_mismatch(0);
+ /*
+ * At the time of a TLB miss/installation
+ * - HW version needs to match SW version
+ * - SW needs to have a valid ASID
+ */
+ if (addr < 0x70000000 &&
+ ((mm_asid == MM_CTXT_NO_ASID) ||
+ (mmu_asid != (mm_asid & MM_CTXT_ASID_MASK))))
+ print_asid_mismatch(mm_asid, mmu_asid, 0);
}
#endif
diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S
index 9df765dc7c3..79bfc81358c 100644
--- a/arch/arc/mm/tlbex.S
+++ b/arch/arc/mm/tlbex.S
@@ -39,22 +39,41 @@
#include <linux/linkage.h>
#include <asm/entry.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/arcregs.h>
#include <asm/cache.h>
#include <asm/processor.h>
-#if (CONFIG_ARC_MMU_VER == 1)
#include <asm/tlb-mmu1.h>
-#endif
-;--------------------------------------------------------------------------
-; scratch memory to save the registers (r0-r3) used to code TLB refill Handler
-; For details refer to comments before TLBMISS_FREEUP_REGS below
+;-----------------------------------------------------------------
+; ARC700 Exception Handling doesn't auto-switch stack and it only provides
+; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
+;
+; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
+; "global" is used to free-up FIRST core reg to be able to code the rest of
+; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
+; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
+; need to be saved as well by extending the "global" to be 4 words. Hence
+; ".size ex_saved_reg1, 16"
+; [All of this dance is to avoid stack switching for each TLB Miss, since we
+; only need to save only a handful of regs, as opposed to complete reg file]
+;
+; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
+; core reg as it will not be SMP safe.
+; Thus scratch AUX reg is used (and no longer used to cache task PGD).
+; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
+; Epilogue thus has to locate the "per-cpu" storage for regs.
+; To avoid cache line bouncing the per-cpu global is aligned/sized per
+; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
+; ".size ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
+
+; As simple as that....
;--------------------------------------------------------------------------
+; scratch memory to save [r0-r3] used to code TLB refill Handler
ARCFP_DATA ex_saved_reg1
- .align 1 << L1_CACHE_SHIFT ; IMP: Must be Cache Line aligned
+ .align 1 << L1_CACHE_SHIFT
.type ex_saved_reg1, @object
#ifdef CONFIG_SMP
.size ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)
@@ -66,6 +85,44 @@ ex_saved_reg1:
.zero 16
#endif
+.macro TLBMISS_FREEUP_REGS
+#ifdef CONFIG_SMP
+ sr r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
+ GET_CPU_ID r0 ; get to per cpu scratch mem,
+ lsl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu
+ add r0, @ex_saved_reg1, r0
+#else
+ st r0, [@ex_saved_reg1]
+ mov_s r0, @ex_saved_reg1
+#endif
+ st_s r1, [r0, 4]
+ st_s r2, [r0, 8]
+ st_s r3, [r0, 12]
+
+ ; VERIFY if the ASID in MMU-PID Reg is same as
+ ; one in Linux data structures
+
+ tlb_paranoid_check_asm
+.endm
+
+.macro TLBMISS_RESTORE_REGS
+#ifdef CONFIG_SMP
+ GET_CPU_ID r0 ; get to per cpu scratch mem
+ lsl r0, r0, L1_CACHE_SHIFT ; each is cache line wide
+ add r0, @ex_saved_reg1, r0
+ ld_s r3, [r0,12]
+ ld_s r2, [r0, 8]
+ ld_s r1, [r0, 4]
+ lr r0, [ARC_REG_SCRATCH_DATA0]
+#else
+ mov_s r0, @ex_saved_reg1
+ ld_s r3, [r0,12]
+ ld_s r2, [r0, 8]
+ ld_s r1, [r0, 4]
+ ld_s r0, [r0]
+#endif
+.endm
+
;============================================================================
; Troubleshooting Stuff
;============================================================================
@@ -76,34 +133,35 @@ ex_saved_reg1:
; In bizzare scenrios SW and HW ASID can get out-of-sync which is trouble.
; So we try to detect this in TLB Mis shandler
-
-.macro DBG_ASID_MISMATCH
+.macro tlb_paranoid_check_asm
#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
- ; make sure h/w ASID is same as s/w ASID
-
GET_CURR_TASK_ON_CPU r3
ld r0, [r3, TASK_ACT_MM]
ld r0, [r0, MM_CTXT+MM_CTXT_ASID]
+ breq r0, 0, 55f ; Error if no ASID allocated
lr r1, [ARC_REG_PID]
and r1, r1, 0xFF
- breq r1, r0, 5f
+ and r2, r0, 0xFF ; MMU PID bits only for comparison
+ breq r1, r2, 5f
+
+55:
; Error if H/w and S/w ASID don't match, but NOT if in kernel mode
- lr r0, [erstatus]
- bbit0 r0, STATUS_U_BIT, 5f
+ lr r2, [erstatus]
+ bbit0 r2, STATUS_U_BIT, 5f
; We sure are in troubled waters, Flag the error, but to do so
; need to switch to kernel mode stack to call error routine
GET_TSK_STACK_BASE r3, sp
; Call printk to shoutout aloud
- mov r0, 1
+ mov r2, 1
j print_asid_mismatch
-5: ; ASIDs match so proceed normally
+5: ; ASIDs match so proceed normally
nop
#endif
@@ -147,9 +205,9 @@ ex_saved_reg1:
#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
and.f 0, r0, _PAGE_PRESENT
bz 1f
- ld r2, [num_pte_not_present]
- add r2, r2, 1
- st r2, [num_pte_not_present]
+ ld r3, [num_pte_not_present]
+ add r3, r3, 1
+ st r3, [num_pte_not_present]
1:
#endif
@@ -161,13 +219,17 @@ ex_saved_reg1:
; IN: r0 = PTE, r1 = ptr to PTE
.macro CONV_PTE_TO_TLB
- and r3, r0, PTE_BITS_IN_PD1 ; Extract permission flags+PFN from PTE
- sr r3, [ARC_REG_TLBPD1] ; these go in PD1
+ and r3, r0, PTE_BITS_RWX ; r w x
+ lsl r2, r3, 3 ; r w x 0 0 0
+ and.f 0, r0, _PAGE_GLOBAL
+ or.z r2, r2, r3 ; r w x r w x
+
+ and r3, r0, PTE_BITS_NON_RWX_IN_PD1 ; Extract PFN+cache bits from PTE
+ or r3, r3, r2
+
+ sr r3, [ARC_REG_TLBPD1] ; these go in PD1
and r2, r0, PTE_BITS_IN_PD0 ; Extract other PTE flags: (V)alid, (G)lb
-#if (CONFIG_ARC_MMU_VER <= 2) /* Neednot be done with v3 onwards */
- lsr r2, r2 ; shift PTE flags to match layout in PD0
-#endif
lr r3,[ARC_REG_TLBPD0] ; MMU prepares PD0 with vaddr and asid
@@ -191,68 +253,6 @@ ex_saved_reg1:
#endif
.endm
-;-----------------------------------------------------------------
-; ARC700 Exception Handling doesn't auto-switch stack and it only provides
-; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
-;
-; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
-; "global" is used to free-up FIRST core reg to be able to code the rest of
-; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
-; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
-; need to be saved as well by extending the "global" to be 4 words. Hence
-; ".size ex_saved_reg1, 16"
-; [All of this dance is to avoid stack switching for each TLB Miss, since we
-; only need to save only a handful of regs, as opposed to complete reg file]
-;
-; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
-; core reg as it will not be SMP safe.
-; Thus scratch AUX reg is used (and no longer used to cache task PGD).
-; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
-; Epilogue thus has to locate the "per-cpu" storage for regs.
-; To avoid cache line bouncing the per-cpu global is aligned/sized per
-; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
-; ".size ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
-
-; As simple as that....
-
-.macro TLBMISS_FREEUP_REGS
-#ifdef CONFIG_SMP
- sr r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
- GET_CPU_ID r0 ; get to per cpu scratch mem,
- lsl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu
- add r0, @ex_saved_reg1, r0
-#else
- st r0, [@ex_saved_reg1]
- mov_s r0, @ex_saved_reg1
-#endif
- st_s r1, [r0, 4]
- st_s r2, [r0, 8]
- st_s r3, [r0, 12]
-
- ; VERIFY if the ASID in MMU-PID Reg is same as
- ; one in Linux data structures
-
- DBG_ASID_MISMATCH
-.endm
-
-;-----------------------------------------------------------------
-.macro TLBMISS_RESTORE_REGS
-#ifdef CONFIG_SMP
- GET_CPU_ID r0 ; get to per cpu scratch mem
- lsl r0, r0, L1_CACHE_SHIFT ; each is cache line wide
- add r0, @ex_saved_reg1, r0
- ld_s r3, [r0,12]
- ld_s r2, [r0, 8]
- ld_s r1, [r0, 4]
- lr r0, [ARC_REG_SCRATCH_DATA0]
-#else
- mov_s r0, @ex_saved_reg1
- ld_s r3, [r0,12]
- ld_s r2, [r0, 8]
- ld_s r1, [r0, 4]
- ld_s r0, [r0]
-#endif
-.endm
ARCFP_CODE ;Fast Path Code, candidate for ICCM
@@ -260,7 +260,7 @@ ARCFP_CODE ;Fast Path Code, candidate for ICCM
; I-TLB Miss Exception Handler
;-----------------------------------------------------------------------------
-ARC_ENTRY EV_TLBMissI
+ENTRY(EV_TLBMissI)
TLBMISS_FREEUP_REGS
@@ -271,35 +271,35 @@ ARC_ENTRY EV_TLBMissI
#endif
;----------------------------------------------------------------
- ; Get the PTE corresponding to V-addr accessed
+ ; Get the PTE corresponding to V-addr accessed, r2 is setup with EFA
LOAD_FAULT_PTE
;----------------------------------------------------------------
; VERIFY_PTE: Check if PTE permissions approp for executing code
cmp_s r2, VMALLOC_START
- mov.lo r2, (_PAGE_PRESENT | _PAGE_READ | _PAGE_EXECUTE)
- mov.hs r2, (_PAGE_PRESENT | _PAGE_K_READ | _PAGE_K_EXECUTE)
+ mov_s r2, (_PAGE_PRESENT | _PAGE_EXECUTE)
+ or.hs r2, r2, _PAGE_GLOBAL
and r3, r0, r2 ; Mask out NON Flag bits from PTE
xor.f r3, r3, r2 ; check ( ( pte & flags_test ) == flags_test )
bnz do_slow_path_pf
; Let Linux VM know that the page was accessed
- or r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED) ; set Accessed Bit
- st_s r0, [r1] ; Write back PTE
+ or r0, r0, _PAGE_ACCESSED ; set Accessed Bit
+ st_s r0, [r1] ; Write back PTE
CONV_PTE_TO_TLB
COMMIT_ENTRY_TO_MMU
TLBMISS_RESTORE_REGS
rtie
-ARC_EXIT EV_TLBMissI
+END(EV_TLBMissI)
;-----------------------------------------------------------------------------
; D-TLB Miss Exception Handler
;-----------------------------------------------------------------------------
-ARC_ENTRY EV_TLBMissD
+ENTRY(EV_TLBMissD)
TLBMISS_FREEUP_REGS
@@ -311,32 +311,27 @@ ARC_ENTRY EV_TLBMissD
;----------------------------------------------------------------
; Get the PTE corresponding to V-addr accessed
- ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE
+ ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE, r2 = EFA
LOAD_FAULT_PTE
;----------------------------------------------------------------
; VERIFY_PTE: Chk if PTE permissions approp for data access (R/W/R+W)
- mov_s r2, 0
+ cmp_s r2, VMALLOC_START
+ mov_s r2, _PAGE_PRESENT ; common bit for K/U PTE
+ or.hs r2, r2, _PAGE_GLOBAL ; kernel PTE only
+
+ ; Linux PTE [RWX] bits are semantically overloaded:
+ ; -If PAGE_GLOBAL set, they refer to kernel-only flags (vmalloc)
+ ; -Otherwise they are user-mode permissions, and those are exactly
+ ; same for kernel mode as well (e.g. copy_(to|from)_user)
+
lr r3, [ecr]
btst_s r3, ECR_C_BIT_DTLB_LD_MISS ; Read Access
or.nz r2, r2, _PAGE_READ ; chk for Read flag in PTE
btst_s r3, ECR_C_BIT_DTLB_ST_MISS ; Write Access
or.nz r2, r2, _PAGE_WRITE ; chk for Write flag in PTE
- ; Above laddering takes care of XCHG access
- ; which is both Read and Write
-
- ; If kernel mode access, ; make _PAGE_xx flags as _PAGE_K_xx
- ; For copy_(to|from)_user, despite exception taken in kernel mode,
- ; this code is not hit, because EFA would still be the user mode
- ; address (EFA < 0x6000_0000).
- ; This code is for legit kernel mode faults, vmalloc specifically
- ; (EFA: 0x7000_0000 to 0x7FFF_FFFF)
-
- lr r3, [efa]
- cmp r3, VMALLOC_START - 1 ; If kernel mode access
- asl.hi r2, r2, 3 ; make _PAGE_xx flags as _PAGE_K_xx
- or r2, r2, _PAGE_PRESENT ; Common flag for K/U mode
+ ; Above laddering takes care of XCHG access (both R and W)
; By now, r2 setup with all the Flags we need to check in PTE
and r3, r0, r2 ; Mask out NON Flag bits from PTE
@@ -345,7 +340,7 @@ ARC_ENTRY EV_TLBMissD
;----------------------------------------------------------------
; UPDATE_PTE: Let Linux VM know that page was accessed/dirty
lr r3, [ecr]
- or r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED) ; Accessed bit always
+ or r0, r0, _PAGE_ACCESSED ; Accessed bit always
btst_s r3, ECR_C_BIT_DTLB_ST_MISS ; See if it was a Write Access ?
or.nz r0, r0, _PAGE_MODIFIED ; if Write, set Dirty bit as well
st_s r0, [r1] ; Write back PTE
@@ -371,28 +366,11 @@ do_slow_path_pf:
; Slow path TLB Miss handled as a regular ARC Exception
; (stack switching / save the complete reg-file).
- ; That requires freeing up r9
- EXCPN_PROLOG_FREEUP_REG r9
-
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ EXCEPTION_PROLOGUE
; ------- setup args for Linux Page fault Hanlder ---------
- mov_s r0, sp
- lr r2, [efa]
- lr r3, [ecr]
-
- ; Both st and ex imply WRITE access of some sort, hence do_page_fault( )
- ; invoked with write=1 for DTLB-st/ex Miss and write=0 for ITLB miss or
- ; DTLB-ld Miss
- ; DTLB Miss Cause code is ld = 0x01 , st = 0x02, ex = 0x03
- ; Following code uses that fact that st/ex have one bit in common
-
- btst_s r3, ECR_C_BIT_DTLB_ST_MISS
- mov.z r1, 0
- mov.nz r1, 1
+ mov_s r1, sp
+ lr r0, [efa]
; We don't want exceptions to be disabled while the fault is handled.
; Now that we have saved the context we return from exception hence
@@ -403,6 +381,4 @@ do_slow_path_pf:
bl do_page_fault
b ret_from_exception
-ARC_EXIT EV_TLBMissD
-
-ARC_ENTRY EV_TLBMissB ; Bogus entry to measure sz of DTLBMiss hdlr
+END(EV_TLBMissD)
diff --git a/arch/arc/plat-arcfpga/Kconfig b/arch/arc/plat-arcfpga/Kconfig
index b41e786cdbc..e27bb5cc3c1 100644
--- a/arch/arc/plat-arcfpga/Kconfig
+++ b/arch/arc/plat-arcfpga/Kconfig
@@ -33,7 +33,6 @@ config ISS_SMP_EXTN
bool "ARC SMP Extensions (ISS Models only)"
default n
depends on SMP
- select ARC_HAS_COH_RTSC
help
SMP Extensions to ARC700, in a "simulation only" Model, supported in
ARC ISS (Instruction Set Simulator).
@@ -49,36 +48,4 @@ config ARC_SERIAL_BAUD
help
Baud rate for the ARC UART
-menuconfig ARC_HAS_BVCI_LAT_UNIT
- bool "BVCI Bus Latency Unit"
- depends on ARC_BOARD_ML509 || ARC_BOARD_ANGEL4
- help
- IP to add artifical latency to BVCI Bus Based FPGA builds.
- The default latency (even worst case) for FPGA is non-realistic
- (~10 SDRAM, ~5 SSRAM).
-
-config BVCI_LAT_UNITS
- hex "Latency Unit(s) Bitmap"
- default "0x0"
- depends on ARC_HAS_BVCI_LAT_UNIT
- help
- There are multiple Latency Units corresponding to the many
- interfaces of the system bus arbiter (both CPU side as well as
- the peripheral side).
- To add latency to ALL memory transaction, choose Unit 0, otherwise
- for finer grainer - interface wise latency, specify a bitmap (1 bit
- per unit) of all units. e.g. 1,2,12 will be 0x1003
-
- Unit 0 - System Arb and Mem Controller
- Unit 1 - I$ and System Bus
- Unit 2 - D$ and System Bus
- ..
- Unit 12 - IDE Disk controller and System Bus
-
-config BVCI_LAT_CYCLES
- int "Latency Value in cycles"
- range 0 63
- default "30"
- depends on ARC_HAS_BVCI_LAT_UNIT
-
endif
diff --git a/arch/arc/plat-arcfpga/Makefile b/arch/arc/plat-arcfpga/Makefile
index a44e22ebc1b..4d1bddc34b5 100644
--- a/arch/arc/plat-arcfpga/Makefile
+++ b/arch/arc/plat-arcfpga/Makefile
@@ -9,4 +9,4 @@
KBUILD_CFLAGS += -Iarch/arc/plat-arcfpga/include
obj-y := platform.o irq.o
-obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_ISS_SMP_EXTN) += smp.o
diff --git a/arch/arc/plat-arcfpga/include/plat/irq.h b/arch/arc/plat-arcfpga/include/plat/irq.h
index 41e335670f6..6adbc53c3a5 100644
--- a/arch/arc/plat-arcfpga/include/plat/irq.h
+++ b/arch/arc/plat-arcfpga/include/plat/irq.h
@@ -16,8 +16,6 @@
#define UART1_IRQ 10
#define UART2_IRQ 11
-#define VMAC_IRQ 6
-
#define IDE_IRQ 13
#define PCI_IRQ 14
#define PS2_IRQ 15
diff --git a/arch/arc/plat-arcfpga/include/plat/memmap.h b/arch/arc/plat-arcfpga/include/plat/memmap.h
index 1663f338808..5c78e6135a1 100644
--- a/arch/arc/plat-arcfpga/include/plat/memmap.h
+++ b/arch/arc/plat-arcfpga/include/plat/memmap.h
@@ -15,8 +15,6 @@
#define UART0_BASE 0xC0FC1000
#define UART1_BASE 0xC0FC1100
-#define VMAC_REG_BASEADDR 0xC0FC2000
-
#define IDE_CONTROLLER_BASE 0xC0FC9000
#define AHB_PCI_HOST_BRG_BASE 0xC0FD0000
diff --git a/arch/arc/plat-arcfpga/platform.c b/arch/arc/plat-arcfpga/platform.c
index 4e20a1a5104..61c7e599738 100644
--- a/arch/arc/plat-arcfpga/platform.c
+++ b/arch/arc/plat-arcfpga/platform.c
@@ -22,61 +22,9 @@
#include <plat/smp.h>
#include <plat/irq.h>
-/*-----------------------BVCI Latency Unit -----------------------------*/
-
-#ifdef CONFIG_ARC_HAS_BVCI_LAT_UNIT
-
-int lat_cycles = CONFIG_BVCI_LAT_CYCLES;
-
-/* BVCI Bus Profiler: Latency Unit */
-static void __init setup_bvci_lat_unit(void)
-{
-#define MAX_BVCI_UNITS 12
-
- unsigned int i;
- unsigned int *base = (unsigned int *)BVCI_LAT_UNIT_BASE;
- const unsigned long units_req = CONFIG_BVCI_LAT_UNITS;
- const unsigned int REG_UNIT = 21;
- const unsigned int REG_VAL = 22;
-
- /*
- * There are multiple Latency Units corresponding to the many
- * interfaces of the system bus arbiter (both CPU side as well as
- * the peripheral side).
- *
- * Unit 0 - System Arb and Mem Controller - adds latency to all
- * memory trasactions
- * Unit 1 - I$ and System Bus
- * Unit 2 - D$ and System Bus
- * ..
- * Unit 12 - IDE Disk controller and System Bus
- *
- * The programmers model requires writing to lat_unit reg first
- * and then the latency value (cycles) to lat_value reg
- */
-
- if (CONFIG_BVCI_LAT_UNITS == 0) {
- writel(0, base + REG_UNIT);
- writel(lat_cycles, base + REG_VAL);
- pr_info("BVCI Latency for all Memory Transactions %d cycles\n",
- lat_cycles);
- } else {
- for_each_set_bit(i, &units_req, MAX_BVCI_UNITS) {
- writel(i + 1, base + REG_UNIT); /* loop is 0 based */
- writel(lat_cycles, base + REG_VAL);
- pr_info("BVCI Latency for Unit[%d] = %d cycles\n",
- (i + 1), lat_cycles);
- }
- }
-}
-#else
-static void __init setup_bvci_lat_unit(void)
-{
-}
-#endif
-
/*----------------------- Platform Devices -----------------------------*/
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
static unsigned long arc_uart_info[] = {
0, /* uart->is_emulated (runtime @running_on_hw) */
0, /* uart->port.uartclk */
@@ -115,7 +63,7 @@ static struct platform_device arc_uart0_dev = {
static struct platform_device *fpga_early_devs[] __initdata = {
&arc_uart0_dev,
};
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
static void arc_fpga_serial_init(void)
{
@@ -131,16 +79,11 @@ static void arc_fpga_serial_init(void)
ARRAY_SIZE(fpga_early_devs));
/*
- * ARC console driver registers itself as an early platform driver
- * of class "earlyprintk".
- * Install it here, followed by probe of devices.
- * The installation here doesn't require earlyprintk in command line
- * To do so however, replace the lines below with
- * parse_early_param();
- * early_platform_driver_probe("earlyprintk", 1, 1);
- * ^^
+ * ARC console driver registers (build time) as an early platform driver
+ * of class "earlyprintk". However it needs explicit cmdline toggle
+ * "earlyprintk=ttyARC0" to be successfuly runtime registered.
+ * Otherwise the early probe below fails to find the driver
*/
- early_platform_driver_register_all("earlyprintk");
early_platform_driver_probe("earlyprintk", 1, 0);
/*
@@ -152,24 +95,27 @@ static void arc_fpga_serial_init(void)
* otherwise the early console never gets a chance to run.
*/
add_preferred_console("ttyARC", 0, "115200");
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
+}
+#else /* !IS_ENABLED(CONFIG_SERIAL_ARC) */
+static void arc_fpga_serial_init(void)
+{
}
+#endif
static void __init plat_fpga_early_init(void)
{
pr_info("[plat-arcfpga]: registering early dev resources\n");
- setup_bvci_lat_unit();
-
arc_fpga_serial_init();
-#ifdef CONFIG_SMP
+#ifdef CONFIG_ISS_SMP_EXTN
iss_model_init_early_smp();
#endif
}
static struct of_dev_auxdata plat_auxdata_lookup[] __initdata = {
-#if defined(CONFIG_SERIAL_ARC) || defined(CONFIG_SERIAL_ARC_MODULE)
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
OF_DEV_AUXDATA("snps,arc-uart", UART0_BASE, "arc-uart", arc_uart_info),
#endif
{}
@@ -195,7 +141,7 @@ static void __init plat_fpga_populate_dev(void)
* callback set, by matching the DT compatible name.
*/
-static const char *aa4_compat[] __initdata = {
+static const char *aa4_compat[] __initconst = {
"snps,arc-angel4",
NULL,
};
@@ -205,12 +151,12 @@ MACHINE_START(ANGEL4, "angel4")
.init_early = plat_fpga_early_init,
.init_machine = plat_fpga_populate_dev,
.init_irq = plat_fpga_init_IRQ,
-#ifdef CONFIG_SMP
+#ifdef CONFIG_ISS_SMP_EXTN
.init_smp = iss_model_init_smp,
#endif
MACHINE_END
-static const char *ml509_compat[] __initdata = {
+static const char *ml509_compat[] __initconst = {
"snps,arc-ml509",
NULL,
};
@@ -224,3 +170,15 @@ MACHINE_START(ML509, "ml509")
.init_smp = iss_model_init_smp,
#endif
MACHINE_END
+
+static const char *nsimosci_compat[] __initconst = {
+ "snps,nsimosci",
+ NULL,
+};
+
+MACHINE_START(NSIMOSCI, "nsimosci")
+ .dt_compat = nsimosci_compat,
+ .init_early = NULL,
+ .init_machine = plat_fpga_populate_dev,
+ .init_irq = NULL,
+MACHINE_END
diff --git a/arch/arc/plat-arcfpga/smp.c b/arch/arc/plat-arcfpga/smp.c
index 91b55349a5f..92bad912207 100644
--- a/arch/arc/plat-arcfpga/smp.c
+++ b/arch/arc/plat-arcfpga/smp.c
@@ -42,6 +42,24 @@ static void iss_model_smp_wakeup_cpu(int cpu, unsigned long pc)
}
+static inline int get_hw_config_num_irq(void)
+{
+ uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
+
+ switch (val & 0x03) {
+ case 0:
+ return 16;
+ case 1:
+ return 32;
+ case 2:
+ return 8;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
/*
* Any SMP specific init any CPU does when it comes up.
* Here we setup the CPU to enable Inter-Processor-Interrupts
@@ -88,18 +106,14 @@ void iss_model_init_smp(unsigned int cpu)
smp_ipi_irq_setup(cpu, IDU_INTERRUPT_0 + cpu);
}
-static void iss_model_ipi_send(void *arg)
+static void iss_model_ipi_send(int cpu)
{
- struct cpumask *callmap = arg;
- unsigned int cpu;
-
- for_each_cpu(cpu, callmap)
- idu_irq_assert(cpu);
+ idu_irq_assert(cpu);
}
-static void iss_model_ipi_clear(int cpu, int irq)
+static void iss_model_ipi_clear(int irq)
{
- idu_irq_clear(IDU_INTERRUPT_0 + cpu);
+ idu_irq_clear(IDU_INTERRUPT_0 + smp_processor_id());
}
void iss_model_init_early_smp(void)
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
new file mode 100644
index 00000000000..6994c188dc8
--- /dev/null
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -0,0 +1,32 @@
+# Abilis Systems TB10x platform kernel configuration file
+#
+# Author: Christian Ruppert <christian.ruppert@abilis.com>
+#
+# 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
+
+
+menuconfig ARC_PLAT_TB10X
+ bool "Abilis TB10x"
+ select COMMON_CLK
+ select PINCTRL
+ select PINCTRL_TB10X
+ select PINMUX
+ select ARCH_REQUIRE_GPIOLIB
+ select GPIO_TB10X
+ select TB10X_IRQC
+ help
+ Support for platforms based on the TB10x home media gateway SOC by
+ Abilis Systems. TB10x is based on the ARC700 CPU architecture.
+ Say Y if you are building a kernel for one of the SOCs in this
+ series (e.g. TB100 or TB101). If in doubt say N.
diff --git a/arch/arc/plat-tb10x/Makefile b/arch/arc/plat-tb10x/Makefile
new file mode 100644
index 00000000000..89611d25ef3
--- /dev/null
+++ b/arch/arc/plat-tb10x/Makefile
@@ -0,0 +1,21 @@
+# Abilis Systems TB10x platform Makefile
+#
+# Author: Christian Ruppert <christian.ruppert@abilis.com>
+#
+# 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
+
+
+KBUILD_CFLAGS += -Iarch/arc/plat-tb10x/include
+
+obj-y += tb10x.o
diff --git a/arch/arc/plat-tb10x/tb10x.c b/arch/arc/plat-tb10x/tb10x.c
new file mode 100644
index 00000000000..06cb3092946
--- /dev/null
+++ b/arch/arc/plat-tb10x/tb10x.c
@@ -0,0 +1,45 @@
+/*
+ * Abilis Systems TB10x platform initialisation
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * 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 <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach_desc.h>
+
+
+static void __init tb10x_platform_init(void)
+{
+ of_clk_init(NULL);
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *tb10x_compat[] __initdata = {
+ "abilis,arc-tb10x",
+ NULL,
+};
+
+MACHINE_START(TB10x, "tb10x")
+ .dt_compat = tb10x_compat,
+ .init_machine = tb10x_platform_init,
+MACHINE_END