aboutsummaryrefslogtreecommitdiff
path: root/arch/metag
diff options
context:
space:
mode:
Diffstat (limited to 'arch/metag')
-rw-r--r--arch/metag/Kconfig17
-rw-r--r--arch/metag/Kconfig.debug7
-rw-r--r--arch/metag/Kconfig.soc14
-rw-r--r--arch/metag/Makefile4
-rw-r--r--arch/metag/boot/.gitignore2
-rw-r--r--arch/metag/boot/dts/Makefile12
l---------arch/metag/boot/dts/include/dt-bindings1
-rw-r--r--arch/metag/boot/dts/skeleton.dts2
-rw-r--r--arch/metag/boot/dts/tz1090.dtsi108
-rw-r--r--arch/metag/boot/dts/tz1090_generic.dts10
-rw-r--r--arch/metag/configs/meta1_defconfig1
-rw-r--r--arch/metag/configs/meta2_defconfig1
-rw-r--r--arch/metag/configs/meta2_smp_defconfig1
-rw-r--r--arch/metag/configs/tz1090_defconfig42
-rw-r--r--arch/metag/include/asm/Kbuild3
-rw-r--r--arch/metag/include/asm/atomic.h6
-rw-r--r--arch/metag/include/asm/barrier.h21
-rw-r--r--arch/metag/include/asm/bitops.h6
-rw-r--r--arch/metag/include/asm/bug.h4
-rw-r--r--arch/metag/include/asm/checksum.h3
-rw-r--r--arch/metag/include/asm/clock.h8
-rw-r--r--arch/metag/include/asm/fixmap.h32
-rw-r--r--arch/metag/include/asm/hugetlb.h1
-rw-r--r--arch/metag/include/asm/irq.h1
-rw-r--r--arch/metag/include/asm/mach/arch.h2
-rw-r--r--arch/metag/include/asm/metag_mem.h3
-rw-r--r--arch/metag/include/asm/pgalloc.h8
-rw-r--r--arch/metag/include/asm/pgtable.h3
-rw-r--r--arch/metag/include/asm/processor.h4
-rw-r--r--arch/metag/include/asm/prom.h23
-rw-r--r--arch/metag/include/asm/setup.h1
-rw-r--r--arch/metag/include/asm/smp.h2
-rw-r--r--arch/metag/include/asm/tbx.h19
-rw-r--r--arch/metag/include/asm/thread_info.h10
-rw-r--r--arch/metag/include/asm/topology.h25
-rw-r--r--arch/metag/include/uapi/asm/Kbuild3
-rw-r--r--arch/metag/include/uapi/asm/ech.h15
-rw-r--r--arch/metag/include/uapi/asm/resource.h7
-rw-r--r--arch/metag/kernel/cachepart.c29
-rw-r--r--arch/metag/kernel/clock.c59
-rw-r--r--arch/metag/kernel/da.c2
-rw-r--r--arch/metag/kernel/devtree.c83
-rw-r--r--arch/metag/kernel/dma.c9
-rw-r--r--arch/metag/kernel/ftrace.c5
-rw-r--r--arch/metag/kernel/head.S8
-rw-r--r--arch/metag/kernel/irq.c75
-rw-r--r--arch/metag/kernel/kick.c9
-rw-r--r--arch/metag/kernel/metag_ksyms.c5
-rw-r--r--arch/metag/kernel/perf/perf_event.c82
-rw-r--r--arch/metag/kernel/process.c37
-rw-r--r--arch/metag/kernel/ptrace.c34
-rw-r--r--arch/metag/kernel/setup.c34
-rw-r--r--arch/metag/kernel/signal.c48
-rw-r--r--arch/metag/kernel/smp.c175
-rw-r--r--arch/metag/kernel/time.c14
-rw-r--r--arch/metag/kernel/topology.c1
-rw-r--r--arch/metag/kernel/traps.c18
-rw-r--r--arch/metag/lib/checksum.c1
-rw-r--r--arch/metag/mm/Kconfig8
-rw-r--r--arch/metag/mm/cache.c2
-rw-r--r--arch/metag/mm/fault.c12
-rw-r--r--arch/metag/mm/init.c76
-rw-r--r--arch/metag/mm/numa.c5
-rw-r--r--arch/metag/oprofile/Makefile17
-rw-r--r--arch/metag/oprofile/backtrace.c63
-rw-r--r--arch/metag/oprofile/backtrace.h6
-rw-r--r--arch/metag/oprofile/common.c66
-rw-r--r--arch/metag/tbx/tbidefr.S2
68 files changed, 887 insertions, 530 deletions
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index afc8973d148..499b7610eaa 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -1,7 +1,3 @@
-config SYMBOL_PREFIX
- string
- default "_"
-
config METAG
def_bool y
select EMBEDDED
@@ -13,11 +9,11 @@ config METAG
select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DEBUG_STACKOVERFLOW
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
- select HAVE_GENERIC_HARDIRQS
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZO
@@ -25,8 +21,10 @@ config METAG
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_MOD_ARCH_SPECIFIC
+ select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UNDERSCORE_SYMBOL_PREFIX
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select OF
@@ -54,10 +52,7 @@ config GENERIC_HWEIGHT
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_GPIO
- def_bool n
-
-config NO_IOPORT
+config NO_IOPORT_MAP
def_bool y
source "init/Kconfig"
@@ -116,7 +111,6 @@ config METAG_META21
config SMP
bool "Symmetric multi-processing support"
depends on METAG_META21 && METAG_META21_MMU
- select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one thread running
Linux. If you have a system with only one thread running Linux,
@@ -209,6 +203,9 @@ config METAG_PERFCOUNTER_IRQS
When disabled, Performance Counters information will be collected
based on Timer Interrupt.
+config HW_PERF_EVENTS
+ def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS
+
config METAG_DA
bool "DA support"
help
diff --git a/arch/metag/Kconfig.debug b/arch/metag/Kconfig.debug
index e45bbf6a7a5..cb5c9286054 100644
--- a/arch/metag/Kconfig.debug
+++ b/arch/metag/Kconfig.debug
@@ -6,13 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-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 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
depends on DEBUG_KERNEL
diff --git a/arch/metag/Kconfig.soc b/arch/metag/Kconfig.soc
index ec079cfb7c6..973640f4675 100644
--- a/arch/metag/Kconfig.soc
+++ b/arch/metag/Kconfig.soc
@@ -14,6 +14,20 @@ config META21_FPGA
help
This is a Meta 2.1 FPGA bitstream, just a bare CPU.
+config SOC_TZ1090
+ bool "Toumaz Xenif TZ1090 SoC (Comet)"
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select IMGPDC_IRQ
+ select METAG_LNKGET_AROUND_CACHE
+ select METAG_META21
+ select METAG_SMP_WRITE_REORDERING
+ select PINCTRL
+ select PINCTRL_TZ1090
+ select PINCTRL_TZ1090_PDC
+ help
+ This is a Toumaz Technology Xenif TZ1090 (A.K.A. Comet) SoC containing
+ a 2-threaded HTP.
+
endchoice
menu "SoC configuration"
diff --git a/arch/metag/Makefile b/arch/metag/Makefile
index 81bd6a1c748..9739857bded 100644
--- a/arch/metag/Makefile
+++ b/arch/metag/Makefile
@@ -20,7 +20,7 @@ checkflags-$(CONFIG_METAG_META12) += -DMETAC_1_2
checkflags-$(CONFIG_METAG_META21) += -DMETAC_2_1
CHECKFLAGS += -D__metag__ $(checkflags-y)
-KBUILD_DEFCONFIG := meta2_defconfig
+KBUILD_DEFCONFIG := tz1090_defconfig
sflags-$(CONFIG_METAG_META12) += -mmetac=1.2
ifeq ($(CONFIG_METAG_META12),y)
@@ -49,6 +49,8 @@ core-y += arch/metag/mm/
libs-y += arch/metag/lib/
libs-y += arch/metag/tbx/
+drivers-$(CONFIG_OPROFILE) += arch/metag/oprofile/
+
boot := arch/metag/boot
boot_targets += uImage
diff --git a/arch/metag/boot/.gitignore b/arch/metag/boot/.gitignore
index a021da20115..2d6c0c16088 100644
--- a/arch/metag/boot/.gitignore
+++ b/arch/metag/boot/.gitignore
@@ -1,4 +1,4 @@
vmlinux*
uImage*
ramdisk.*
-*.dtb
+*.dtb*
diff --git a/arch/metag/boot/dts/Makefile b/arch/metag/boot/dts/Makefile
index e0b5afd8bde..72c12187942 100644
--- a/arch/metag/boot/dts/Makefile
+++ b/arch/metag/boot/dts/Makefile
@@ -1,16 +1,22 @@
dtb-y += skeleton.dtb
+dtb-y += tz1090_generic.dtb
# Built-in dtb
builtindtb-y := skeleton
+builtindtb-$(CONFIG_SOC_TZ1090) := tz1090_generic
ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"")
- builtindtb-y := $(CONFIG_METAG_BUILTIN_DTB_NAME)
+ builtindtb-y := $(patsubst "%",%,$(CONFIG_METAG_BUILTIN_DTB_NAME))
endif
-obj-$(CONFIG_METAG_BUILTIN_DTB) += $(patsubst "%",%,$(builtindtb-y)).dtb.o
+
+dtb-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb
+obj-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb.o
targets += dtbs
targets += $(dtb-y)
+.SECONDARY: $(obj)/$(builtindtb-y).dtb.S
+
dtbs: $(addprefix $(obj)/, $(dtb-y))
-clean-files += *.dtb
+clean-files += *.dtb *.dtb.S
diff --git a/arch/metag/boot/dts/include/dt-bindings b/arch/metag/boot/dts/include/dt-bindings
new file mode 120000
index 00000000000..08c00e4972f
--- /dev/null
+++ b/arch/metag/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings \ No newline at end of file
diff --git a/arch/metag/boot/dts/skeleton.dts b/arch/metag/boot/dts/skeleton.dts
index 7244d1f0d55..7a49aeb365d 100644
--- a/arch/metag/boot/dts/skeleton.dts
+++ b/arch/metag/boot/dts/skeleton.dts
@@ -7,4 +7,4 @@
*/
/dts-v1/;
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
diff --git a/arch/metag/boot/dts/tz1090.dtsi b/arch/metag/boot/dts/tz1090.dtsi
new file mode 100644
index 00000000000..24ea7d2e913
--- /dev/null
+++ b/arch/metag/boot/dts/tz1090.dtsi
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "skeleton.dtsi"
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ compatible = "toumaz,tz1090", "img,meta";
+
+ interrupt-parent = <&intc>;
+
+ intc: interrupt-controller {
+ compatible = "img,meta-intc";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-banks = <2>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pdc: pdc@0x02006000 {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ reg = <0x02006000 0x1000>;
+ compatible = "img,pdc-intc";
+
+ num-perips = <3>;
+ num-syswakes = <3>;
+
+ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>, /* Syswakes */
+ <30 IRQ_TYPE_LEVEL_HIGH>, /* Perip 0 (RTC) */
+ <29 IRQ_TYPE_LEVEL_HIGH>, /* Perip 1 (IR) */
+ <31 IRQ_TYPE_LEVEL_HIGH>; /* Perip 2 (WDT) */
+ };
+
+ pinctrl: pinctrl@02005800 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pinctrl";
+ reg = <0x02005800 0xe4>;
+ };
+
+ pdc_pinctrl: pinctrl@02006500 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pdc-pinctrl";
+ reg = <0x02006500 0x100>;
+ };
+
+ gpios: gpios@02005800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "img,tz1090-gpio";
+ reg = <0x02005800 0x90>;
+
+ gpios0: bank@0 {
+ gpio-controller;
+ interrupt-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ reg = <0>;
+ interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 0 30>;
+ };
+ gpios1: bank@1 {
+ gpio-controller;
+ interrupt-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ reg = <1>;
+ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 30 30>;
+ };
+ gpios2: bank@2 {
+ gpio-controller;
+ interrupt-controller;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ reg = <2>;
+ interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 60 30>;
+ };
+ };
+
+ pdc_gpios: gpios@02006500 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ compatible = "img,tz1090-pdc-gpio";
+ reg = <0x02006500 0x100>;
+
+ interrupt-parent = <&pdc>;
+ interrupts = <8 IRQ_TYPE_NONE>,
+ <9 IRQ_TYPE_NONE>,
+ <10 IRQ_TYPE_NONE>;
+ gpio-ranges = <&pdc_pinctrl 0 0 7>;
+ };
+ };
+};
diff --git a/arch/metag/boot/dts/tz1090_generic.dts b/arch/metag/boot/dts/tz1090_generic.dts
new file mode 100644
index 00000000000..f9609095596
--- /dev/null
+++ b/arch/metag/boot/dts/tz1090_generic.dts
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2012 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "tz1090.dtsi"
diff --git a/arch/metag/configs/meta1_defconfig b/arch/metag/configs/meta1_defconfig
index c35a75e8ecf..01cd67e4403 100644
--- a/arch/metag/configs/meta1_defconfig
+++ b/arch/metag/configs/meta1_defconfig
@@ -1,6 +1,5 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_defconfig b/arch/metag/configs/meta2_defconfig
index fb314841018..643392ba7ed 100644
--- a/arch/metag/configs/meta2_defconfig
+++ b/arch/metag/configs/meta2_defconfig
@@ -1,7 +1,6 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_smp_defconfig b/arch/metag/configs/meta2_smp_defconfig
index 6c7b777ac27..f3306737da2 100644
--- a/arch/metag/configs/meta2_smp_defconfig
+++ b/arch/metag/configs/meta2_smp_defconfig
@@ -1,7 +1,6 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/tz1090_defconfig b/arch/metag/configs/tz1090_defconfig
new file mode 100644
index 00000000000..9f9316a6df2
--- /dev/null
+++ b/arch/metag/configs/tz1090_defconfig
@@ -0,0 +1,42 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SOC_TZ1090=y
+CONFIG_METAG_HALT_ON_PANIC=y
+# CONFIG_METAG_FPU is not set
+CONFIG_METAG_DA=y
+CONFIG_HZ_100=y
+CONFIG_DEVTMPFS=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_DA_TTY=y
+CONFIG_DA_CONSOLE=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIOLIB=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index 6ae0ccb632c..c29ead89a31 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -13,6 +13,7 @@ generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -23,6 +24,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 += msgbuf.h
generic-y += mutex.h
generic-y += param.h
@@ -30,6 +32,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += sembuf.h
diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h
index 307ecd2bd9a..470e365f04e 100644
--- a/arch/metag/include/asm/atomic.h
+++ b/arch/metag/include/asm/atomic.h
@@ -4,6 +4,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/cmpxchg.h>
+#include <asm/barrier.h>
#if defined(CONFIG_METAG_ATOMICITY_IRQSOFF)
/* The simple UP case. */
@@ -39,11 +40,6 @@
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-#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()
-
#endif
#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h
index c90bfc6bf64..c7591e80067 100644
--- a/arch/metag/include/asm/barrier.h
+++ b/arch/metag/include/asm/barrier.h
@@ -15,6 +15,7 @@ static inline void wr_fence(void)
volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_FENCE;
barrier();
*flushptr = 0;
+ barrier();
}
#else /* CONFIG_METAG_META21 */
@@ -35,6 +36,7 @@ static inline void wr_fence(void)
*flushptr = 0;
*flushptr = 0;
*flushptr = 0;
+ barrier();
}
#endif /* !CONFIG_METAG_META21 */
@@ -68,6 +70,7 @@ static inline void fence(void)
volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_ATOMIC_UNLOCK;
barrier();
*flushptr = 0;
+ barrier();
}
#define smp_mb() fence()
#define smp_rmb() fence()
@@ -82,4 +85,22 @@ static inline void fence(void)
#define smp_read_barrier_depends() do { } while (0)
#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
+#define smp_store_release(p, v) \
+do { \
+ compiletime_assert_atomic_type(*p); \
+ smp_mb(); \
+ ACCESS_ONCE(*p) = (v); \
+} while (0)
+
+#define smp_load_acquire(p) \
+({ \
+ typeof(*p) ___p1 = ACCESS_ONCE(*p); \
+ compiletime_assert_atomic_type(*p); \
+ smp_mb(); \
+ ___p1; \
+})
+
+#define smp_mb__before_atomic() barrier()
+#define smp_mb__after_atomic() barrier()
+
#endif /* _ASM_METAG_BARRIER_H */
diff --git a/arch/metag/include/asm/bitops.h b/arch/metag/include/asm/bitops.h
index c0d0df0d137..2671134ee74 100644
--- a/arch/metag/include/asm/bitops.h
+++ b/arch/metag/include/asm/bitops.h
@@ -5,12 +5,6 @@
#include <asm/barrier.h>
#include <asm/global_lock.h>
-/*
- * clear_bit() doesn't provide any barrier for the compiler.
- */
-#define smp_mb__before_clear_bit() barrier()
-#define smp_mb__after_clear_bit() barrier()
-
#ifdef CONFIG_SMP
/*
* These functions are the basis of our bit ops.
diff --git a/arch/metag/include/asm/bug.h b/arch/metag/include/asm/bug.h
index d04b48cefec..9f8967f10f8 100644
--- a/arch/metag/include/asm/bug.h
+++ b/arch/metag/include/asm/bug.h
@@ -6,7 +6,7 @@
struct pt_regs;
extern const char *trap_name(int trapno);
-extern void die(const char *str, struct pt_regs *regs, long err,
- unsigned long addr) __attribute__ ((noreturn));
+extern void __noreturn die(const char *str, struct pt_regs *regs, long err,
+ unsigned long addr);
#endif
diff --git a/arch/metag/include/asm/checksum.h b/arch/metag/include/asm/checksum.h
index 999bf761a73..08dd1cc6579 100644
--- a/arch/metag/include/asm/checksum.h
+++ b/arch/metag/include/asm/checksum.h
@@ -64,7 +64,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__wsum sum)
{
unsigned long len_proto = (proto + len) << 8;
- asm ("ADD %0, %0, %1\n"
+ asm ("ADDS %0, %0, %1\n"
+ "ADDCS %0, %0, #1\n"
"ADDS %0, %0, %2\n"
"ADDCS %0, %0, #1\n"
"ADDS %0, %0, %3\n"
diff --git a/arch/metag/include/asm/clock.h b/arch/metag/include/asm/clock.h
index 3e2915a280c..ded4ab2e1fd 100644
--- a/arch/metag/include/asm/clock.h
+++ b/arch/metag/include/asm/clock.h
@@ -19,6 +19,8 @@
* core frequency will be determined like this:
* Meta 1: based on loops_per_jiffy.
* Meta 2: (EXPAND_TIMER_DIV + 1) MHz.
+ * If a "core" clock is provided by the device tree, it
+ * will override this function.
*/
struct meta_clock_desc {
unsigned long (*get_core_freq)(void);
@@ -27,6 +29,12 @@ struct meta_clock_desc {
extern struct meta_clock_desc _meta_clock;
/*
+ * Perform platform clock initialisation, reading clocks from device tree etc.
+ * Only accessible during boot.
+ */
+void init_metag_clocks(void);
+
+/*
* Set up the default clock, ensuring all callbacks are valid - only accessible
* during boot.
*/
diff --git a/arch/metag/include/asm/fixmap.h b/arch/metag/include/asm/fixmap.h
index 33312751c92..af621b04173 100644
--- a/arch/metag/include/asm/fixmap.h
+++ b/arch/metag/include/asm/fixmap.h
@@ -51,37 +51,7 @@ enum fixed_addresses {
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START ((FIXADDR_TOP - FIXADDR_SIZE) & PMD_MASK)
-#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
-#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
-
-extern void __this_fixmap_does_not_exist(void);
-/*
- * 'index to address' translation. If anyone tries to use the idx
- * directly without tranlation, we catch the bug with a NULL-deference
- * kernel oops. Illegal ranges of incoming indices are caught too.
- */
-static inline unsigned long fix_to_virt(const unsigned int idx)
-{
- /*
- * this branch gets completely eliminated after inlining,
- * except when someone tries to use fixaddr indices in an
- * illegal way. (such as mixing up address types or using
- * out-of-range indices).
- *
- * If it doesn't get removed, the linker will complain
- * loudly with a reasonably clear error message..
- */
- if (idx >= __end_of_fixed_addresses)
- __this_fixmap_does_not_exist();
-
- return __fix_to_virt(idx);
-}
-
-static inline unsigned long virt_to_fix(const unsigned long vaddr)
-{
- BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
- return __virt_to_fix(vaddr);
-}
+#include <asm-generic/fixmap.h>
#define kmap_get_fixmap_pte(vaddr) \
pte_offset_kernel( \
diff --git a/arch/metag/include/asm/hugetlb.h b/arch/metag/include/asm/hugetlb.h
index f545477e61f..471f481e67f 100644
--- a/arch/metag/include/asm/hugetlb.h
+++ b/arch/metag/include/asm/hugetlb.h
@@ -2,6 +2,7 @@
#define _ASM_METAG_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/metag/include/asm/irq.h b/arch/metag/include/asm/irq.h
index be0c8f3c5a5..ad6bd0edbc3 100644
--- a/arch/metag/include/asm/irq.h
+++ b/arch/metag/include/asm/irq.h
@@ -17,6 +17,7 @@ struct pt_regs;
int tbisig_map(unsigned int hw);
extern void do_IRQ(int irq, struct pt_regs *regs);
+extern void init_IRQ(void);
#ifdef CONFIG_METAG_SUSPEND_MEM
int traps_save_context(void);
diff --git a/arch/metag/include/asm/mach/arch.h b/arch/metag/include/asm/mach/arch.h
index 12c5664fea6..433f94624fa 100644
--- a/arch/metag/include/asm/mach/arch.h
+++ b/arch/metag/include/asm/mach/arch.h
@@ -53,7 +53,7 @@ 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
diff --git a/arch/metag/include/asm/metag_mem.h b/arch/metag/include/asm/metag_mem.h
index 3f7b54d8cca..aa5a076df43 100644
--- a/arch/metag/include/asm/metag_mem.h
+++ b/arch/metag/include/asm/metag_mem.h
@@ -700,6 +700,9 @@
#define SYSC_xCPARTG_AND_S 8
#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */
#define SYSC_xCPARTL_OR_S 16
+#ifdef METAC_2_1
+#define SYSC_DCPART_GCON_BIT 0x00100000 /* Coherent shared local */
+#endif /* METAC_2_1 */
#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */
#define SYSC_xCPARTG_OR_S 24
#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */
diff --git a/arch/metag/include/asm/pgalloc.h b/arch/metag/include/asm/pgalloc.h
index 275d9285141..3104df0a482 100644
--- a/arch/metag/include/asm/pgalloc.h
+++ b/arch/metag/include/asm/pgalloc.h
@@ -52,8 +52,12 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
{
struct page *pte;
pte = alloc_pages(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO, 0);
- if (pte)
- pgtable_page_ctor(pte);
+ if (!pte)
+ return NULL;
+ if (!pgtable_page_ctor(pte)) {
+ __free_page(pte);
+ return NULL;
+ }
return pte;
}
diff --git a/arch/metag/include/asm/pgtable.h b/arch/metag/include/asm/pgtable.h
index 1cd13d59519..0d9dc548729 100644
--- a/arch/metag/include/asm/pgtable.h
+++ b/arch/metag/include/asm/pgtable.h
@@ -333,9 +333,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1)
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
- remap_pfn_range(vma, vaddr, pfn, size, prot)
-
/*
* No page table caches to initialise
*/
diff --git a/arch/metag/include/asm/processor.h b/arch/metag/include/asm/processor.h
index 9b029a7911c..a8a37477c66 100644
--- a/arch/metag/include/asm/processor.h
+++ b/arch/metag/include/asm/processor.h
@@ -22,6 +22,8 @@
/* Add an extra page of padding at the top of the stack for the guard page. */
#define STACK_TOP (TASK_SIZE - PAGE_SIZE)
#define STACK_TOP_MAX STACK_TOP
+/* Maximum virtual space for stack */
+#define STACK_SIZE_MAX (CONFIG_MAX_STACK_SIZE_MB*1024*1024)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
@@ -199,4 +201,6 @@ extern void (*soc_halt)(void);
extern void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs);
+extern const struct seq_operations cpuinfo_op;
+
#endif
diff --git a/arch/metag/include/asm/prom.h b/arch/metag/include/asm/prom.h
deleted file mode 100644
index d2aa35d2228..00000000000
--- a/arch/metag/include/asm/prom.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/metag/include/asm/prom.h
- *
- * Copyright (C) 2012 Imagination Technologies Ltd.
- *
- * Based on ARM version:
- * Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.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_METAG_PROM_H
-#define __ASM_METAG_PROM_H
-
-#include <asm/setup.h>
-#define HAVE_ARCH_DEVTREE_FIXUPS
-
-extern struct machine_desc *setup_machine_fdt(void *dt);
-extern void copy_fdt(void);
-
-#endif /* __ASM_METAG_PROM_H */
diff --git a/arch/metag/include/asm/setup.h b/arch/metag/include/asm/setup.h
index e13083b15dd..e9fdee9452b 100644
--- a/arch/metag/include/asm/setup.h
+++ b/arch/metag/include/asm/setup.h
@@ -3,6 +3,7 @@
#include <uapi/asm/setup.h>
+extern const struct machine_desc *setup_machine_fdt(void *dt);
void per_cpu_trap_init(unsigned long);
extern void __init dump_machine_table(void);
#endif /* _ASM_METAG_SETUP_H */
diff --git a/arch/metag/include/asm/smp.h b/arch/metag/include/asm/smp.h
index e0373f81a11..1d7e770f7a5 100644
--- a/arch/metag/include/asm/smp.h
+++ b/arch/metag/include/asm/smp.h
@@ -7,13 +7,11 @@
enum ipi_msg_type {
IPI_CALL_FUNC,
- IPI_CALL_FUNC_SINGLE,
IPI_RESCHEDULE,
};
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
asmlinkage void secondary_start_kernel(void);
diff --git a/arch/metag/include/asm/tbx.h b/arch/metag/include/asm/tbx.h
index 287b36ff8ad..703b9cb0ac5 100644
--- a/arch/metag/include/asm/tbx.h
+++ b/arch/metag/include/asm/tbx.h
@@ -150,11 +150,9 @@
#else
/* Reserved 0x04-0x09 */
#endif
-#define TBID_SIGNUM_SWS 0x0A /* KICK received with SigMask != 0 */
-#define TBID_SIGNUM_SWK 0x0B /* KICK received with SigMask == 0 */
-/* Reserved 0x0C-0x0F */
+/* Reserved 0x0A-0x0F */
#define TBID_SIGNUM_TRT 0x10 /* Timer trigger */
-#define TBID_SIGNUM_LWK 0x11 /* Low level kick (handler provided by TBI) */
+#define TBID_SIGNUM_LWK 0x11 /* Low level kick */
#define TBID_SIGNUM_XXF 0x12 /* Fault handler - receives ALL _xxF sigs */
#ifdef TBI_1_4
#define TBID_SIGNUM_DFR 0x13 /* Deferred Exception handler */
@@ -183,8 +181,7 @@
each hardware signal, sometimes this is a many-to-one relationship. */
#define TBI_TRIG_BIT(SigNum) (\
((SigNum) >= TBID_SIGNUM_TRT) ? 1<<((SigNum)-TBID_SIGNUM_TRT) :\
- ( ((SigNum) == TBID_SIGNUM_SWS) || \
- ((SigNum) == TBID_SIGNUM_SWK) ) ? \
+ ((SigNum) == TBID_SIGNUM_LWK) ? \
TXSTAT_KICK_BIT : TXSTATI_BGNDHALT_BIT )
/* Return the hardware trigger vector number for entries in the
@@ -687,10 +684,8 @@ typedef union _tbires_tag_ {
Triggers will indicate the status of TXSTAT or TXSTATI sampled by the
code that called the handler.
- InstOrSWSId is defined firstly as 'Inst' if the SigNum is TBID_SIGNUM_SWx
- and hold the actual SWITCH instruction detected, secondly if SigNum
- is TBID_SIGNUM_SWS the 'SWSId' is defined to hold the Id of the
- software signal detected, in other cases the value of this
+ Inst is defined as 'Inst' if the SigNum is TBID_SIGNUM_SWx and holds the
+ actual SWITCH instruction detected, in other cases the value of this
parameter is undefined.
pTBI points at the PTBI structure related to the thread and processing
@@ -709,7 +704,7 @@ typedef union _tbires_tag_ {
*/
typedef TBIRES (*PTBIAPIFN)( TBIRES State, int SigNum,
- int Triggers, int InstOrSWSId,
+ int Triggers, int Inst,
volatile struct _tbi_tag_ *pTBI );
#endif /* ifndef __ASSEMBLY__ */
@@ -757,7 +752,7 @@ typedef volatile struct _tbi_tag_ {
#ifndef __ASSEMBLY__
/* This handler should be used for TBID_SIGNUM_DFR */
extern TBIRES __TBIHandleDFR ( TBIRES State, int SigNum,
- int Triggers, int InstOrSWSId,
+ int Triggers, int Inst,
volatile struct _tbi_tag_ *pTBI );
#endif
#endif
diff --git a/arch/metag/include/asm/thread_info.h b/arch/metag/include/asm/thread_info.h
index 0ecd34d8b5f..47711336119 100644
--- a/arch/metag/include/asm/thread_info.h
+++ b/arch/metag/include/asm/thread_info.h
@@ -46,8 +46,6 @@ struct thread_info {
#endif
-#define PREEMPT_ACTIVE 0x10000000
-
#ifdef CONFIG_4KSTACKS
#define THREAD_SHIFT 12
#else
@@ -119,10 +117,8 @@ static inline int kstack_end(void *addr)
#define TIF_SECCOMP 5 /* secure computing */
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
-#define TIF_POLLING_NRFLAG 8 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
-#define TIF_MEMDIE 9 /* is terminating due to OOM killer */
-#define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint instrumentation */
+#define TIF_MEMDIE 8 /* is terminating due to OOM killer */
+#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -150,6 +146,4 @@ static inline int kstack_end(void *addr)
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/metag/include/asm/topology.h b/arch/metag/include/asm/topology.h
index 23f5118f58d..e95f874ded1 100644
--- a/arch/metag/include/asm/topology.h
+++ b/arch/metag/include/asm/topology.h
@@ -3,31 +3,6 @@
#ifdef CONFIG_NUMA
-/* sched_domains SD_NODE_INIT for Meta machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_FORK \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-
#define cpu_to_node(cpu) ((void)(cpu), 0)
#define parent_node(node) ((void)(node), 0)
diff --git a/arch/metag/include/uapi/asm/Kbuild b/arch/metag/include/uapi/asm/Kbuild
index 876c71f866d..ab78be2b6eb 100644
--- a/arch/metag/include/uapi/asm/Kbuild
+++ b/arch/metag/include/uapi/asm/Kbuild
@@ -2,12 +2,13 @@
include include/uapi/asm-generic/Kbuild.asm
header-y += byteorder.h
+header-y += ech.h
header-y += ptrace.h
-header-y += resource.h
header-y += sigcontext.h
header-y += siginfo.h
header-y += swab.h
header-y += unistd.h
generic-y += mman.h
+generic-y += resource.h
generic-y += setup.h
diff --git a/arch/metag/include/uapi/asm/ech.h b/arch/metag/include/uapi/asm/ech.h
new file mode 100644
index 00000000000..ac94d1cf9be
--- /dev/null
+++ b/arch/metag/include/uapi/asm/ech.h
@@ -0,0 +1,15 @@
+#ifndef _UAPI_METAG_ECH_H
+#define _UAPI_METAG_ECH_H
+
+/*
+ * These bits can be set in the top half of the D0.8 register when DSP context
+ * switching is enabled, in order to support partial DSP context save/restore.
+ */
+
+#define TBICTX_XEXT_BIT 0x1000 /* Enable extended context save */
+#define TBICTX_XTDP_BIT 0x0800 /* DSP accumulators/RAM/templates */
+#define TBICTX_XHL2_BIT 0x0400 /* Hardware loops */
+#define TBICTX_XAXX_BIT 0x0200 /* Extended AX registers (A*.4-7) */
+#define TBICTX_XDX8_BIT 0x0100 /* Extended DX registers (D*.8-15) */
+
+#endif /* _UAPI_METAG_ECH_H */
diff --git a/arch/metag/include/uapi/asm/resource.h b/arch/metag/include/uapi/asm/resource.h
deleted file mode 100644
index 526d23cc305..00000000000
--- a/arch/metag/include/uapi/asm/resource.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _UAPI_METAG_RESOURCE_H
-#define _UAPI_METAG_RESOURCE_H
-
-#define _STK_LIM_MAX (1 << 28)
-#include <asm-generic/resource.h>
-
-#endif /* _UAPI_METAG_RESOURCE_H */
diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index 3a589dfb966..0a2385fa2a1 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -24,15 +24,21 @@
unsigned int get_dcache_size(void)
{
unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
- return 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
- >> METAC_CORECFG2_DCSZ_S);
+ unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
+ >> METAC_CORECFG2_DCSZ_S);
+ if (config2 & METAC_CORECFG2_DCSMALL_BIT)
+ sz >>= 6;
+ return sz;
}
unsigned int get_icache_size(void)
{
unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
- return 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
- >> METAC_CORE_C2ICSZ_S);
+ unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
+ >> METAC_CORE_C2ICSZ_S);
+ if (config2 & METAC_CORECFG2_ICSMALL_BIT)
+ sz >>= 6;
+ return sz;
}
unsigned int get_global_dcache_size(void)
@@ -61,7 +67,7 @@ static unsigned int get_thread_cache_size(unsigned int cache, int thread_id)
return 0;
#if PAGE_OFFSET >= LINGLOBAL_BASE
/* Checking for global cache */
- cache_size = (cache == DCACHE ? get_global_dache_size() :
+ cache_size = (cache == DCACHE ? get_global_dcache_size() :
get_global_icache_size());
offset = 8;
#else
@@ -94,22 +100,23 @@ void check_for_cache_aliasing(int thread_id)
thread_cache_size =
get_thread_cache_size(cache_type, thread_id);
if (thread_cache_size < 0)
- pr_emerg("Can't read %s cache size", \
+ pr_emerg("Can't read %s cache size\n",
cache_type ? "DCACHE" : "ICACHE");
else if (thread_cache_size == 0)
/* Cache is off. No need to check for aliasing */
continue;
if (thread_cache_size / CACHE_ASSOCIATIVITY > PAGE_SIZE) {
- pr_emerg("Cache aliasing detected in %s on Thread %d",
+ pr_emerg("Potential cache aliasing detected in %s on Thread %d\n",
cache_type ? "DCACHE" : "ICACHE", thread_id);
- pr_warn("Total %s size: %u bytes",
- cache_type ? "DCACHE" : "ICACHE ",
+ pr_warn("Total %s size: %u bytes\n",
+ cache_type ? "DCACHE" : "ICACHE",
cache_type ? get_dcache_size()
: get_icache_size());
- pr_warn("Thread %s size: %d bytes",
+ pr_warn("Thread %s size: %d bytes\n",
cache_type ? "CACHE" : "ICACHE",
thread_cache_size);
- pr_warn("Page Size: %lu bytes", PAGE_SIZE);
+ pr_warn("Page Size: %lu bytes\n", PAGE_SIZE);
+ panic("Potential cache aliasing detected");
}
}
}
diff --git a/arch/metag/kernel/clock.c b/arch/metag/kernel/clock.c
index defc84056f1..6339c9c6d0a 100644
--- a/arch/metag/kernel/clock.c
+++ b/arch/metag/kernel/clock.c
@@ -8,8 +8,10 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <asm/param.h>
#include <asm/clock.h>
@@ -34,8 +36,63 @@ static unsigned long get_core_freq_default(void)
#endif
}
+static struct clk *clk_core;
+
+/* Clk based get_core_freq callback. */
+static unsigned long get_core_freq_clk(void)
+{
+ return clk_get_rate(clk_core);
+}
+
+/**
+ * init_metag_core_clock() - Set up core clock from devicetree.
+ *
+ * Checks to see if a "core" clock is provided in the device tree, and overrides
+ * the get_core_freq callback to use it.
+ */
+static void __init init_metag_core_clock(void)
+{
+ /*
+ * See if a core clock is provided by the devicetree (and
+ * registered by the init callback above).
+ */
+ struct device_node *node;
+ node = of_find_compatible_node(NULL, NULL, "img,meta");
+ if (!node) {
+ pr_warn("%s: no compatible img,meta DT node found\n",
+ __func__);
+ return;
+ }
+
+ clk_core = of_clk_get_by_name(node, "core");
+ if (IS_ERR(clk_core)) {
+ pr_warn("%s: no core clock found in DT\n",
+ __func__);
+ return;
+ }
+
+ /*
+ * Override the core frequency callback to use
+ * this clk.
+ */
+ _meta_clock.get_core_freq = get_core_freq_clk;
+}
+
+/**
+ * init_metag_clocks() - Set up clocks from devicetree.
+ *
+ * Set up important clocks from device tree. In particular any needed for clock
+ * sources.
+ */
+void __init init_metag_clocks(void)
+{
+ init_metag_core_clock();
+
+ pr_info("Core clock frequency: %lu Hz\n", get_coreclock());
+}
+
/**
- * setup_meta_clocks() - Set up the Meta clock.
+ * setup_meta_clocks() - Early set up of the Meta clock.
* @desc: Clock descriptor usually provided by machine description
*
* Ensures all callbacks are valid.
diff --git a/arch/metag/kernel/da.c b/arch/metag/kernel/da.c
index 52aabb658fd..a35dbed6fff 100644
--- a/arch/metag/kernel/da.c
+++ b/arch/metag/kernel/da.c
@@ -5,12 +5,14 @@
*/
+#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <asm/da.h>
#include <asm/metag_mem.h>
bool _metag_da_present;
+EXPORT_SYMBOL_GPL(_metag_da_present);
int __init metag_da_probe(void)
{
diff --git a/arch/metag/kernel/devtree.c b/arch/metag/kernel/devtree.c
index 7cd02529636..18dd7aea9fd 100644
--- a/arch/metag/kernel/devtree.c
+++ b/arch/metag/kernel/devtree.c
@@ -34,6 +34,19 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
return alloc_bootmem_align(size, align);
}
+static const void * __init arch_get_next_mach(const char *const **match)
+{
+ 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;
+}
+
/**
* setup_machine_fdt - Machine setup when an dtb was passed to the kernel
* @dt: virtual address pointer to dt blob
@@ -41,74 +54,18 @@ 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, *mdesc_best = NULL;
- unsigned int score, mdesc_score = ~1;
- unsigned long dt_root;
- const char *model;
+ const struct machine_desc *mdesc;
/* check device tree validity */
- if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)
+ if (!early_init_dt_scan(dt))
return NULL;
- /* Search the mdescs for the 'best' compatible value match */
- initial_boot_params = devtree;
- dt_root = of_get_flat_dt_root();
-
- 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("\nError: unrecognized/unsupported device tree compatible 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)
dump_machine_table(); /* does not return */
- }
-
- model = of_get_flat_dt_prop(dt_root, "model", NULL);
- if (!model)
- model = of_get_flat_dt_prop(dt_root, "compatible", NULL);
- if (!model)
- model = "<unknown>";
- pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);
-
- /* Retrieve various information from the /chosen node */
- of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
-
- return mdesc_best;
-}
+ pr_info("Machine name: %s\n", mdesc->name);
-/**
- * copy_fdt - Copy device tree into non-init memory.
- *
- * We must copy the flattened device tree blob into non-init memory because the
- * unflattened device tree will reference the strings in it directly.
- */
-void __init copy_fdt(void)
-{
- void *alloc = early_init_dt_alloc_memory_arch(
- be32_to_cpu(initial_boot_params->totalsize), 0x40);
- if (alloc) {
- memcpy(alloc, initial_boot_params,
- be32_to_cpu(initial_boot_params->totalsize));
- initial_boot_params = alloc;
- }
+ return mdesc;
}
diff --git a/arch/metag/kernel/dma.c b/arch/metag/kernel/dma.c
index 8c00dedadc5..c700d625067 100644
--- a/arch/metag/kernel/dma.c
+++ b/arch/metag/kernel/dma.c
@@ -305,9 +305,7 @@ void dma_free_coherent(struct device *dev, size_t size,
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
- ClearPageReserved(page);
-
- __free_page(page);
+ __free_reserved_page(page);
continue;
}
}
@@ -401,11 +399,6 @@ static int __init dma_alloc_init(void)
pgd = pgd_offset(&init_mm, CONSISTENT_START);
pud = pud_alloc(&init_mm, pgd, CONSISTENT_START);
pmd = pmd_alloc(&init_mm, pud, CONSISTENT_START);
- if (!pmd) {
- pr_err("%s: no pmd tables\n", __func__);
- ret = -ENOMEM;
- break;
- }
WARN_ON(!pmd_none(*pmd));
pte = pte_alloc_kernel(pmd, CONSISTENT_START);
diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c
index a774f321643..ed1d685157c 100644
--- a/arch/metag/kernel/ftrace.c
+++ b/arch/metag/kernel/ftrace.c
@@ -117,10 +117,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
}
/* run from kstop_machine */
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* The return code is returned via data */
- writel(0, data);
-
return 0;
}
diff --git a/arch/metag/kernel/head.S b/arch/metag/kernel/head.S
index 969dffabc03..713f71d1bdf 100644
--- a/arch/metag/kernel/head.S
+++ b/arch/metag/kernel/head.S
@@ -1,6 +1,7 @@
! Copyright 2005,2006,2007,2009 Imagination Technologies
#include <linux/init.h>
+#include <asm/metag_mem.h>
#include <generated/asm-offsets.h>
#undef __exit
@@ -48,6 +49,13 @@ __exit:
.global _secondary_startup
.type _secondary_startup,function
_secondary_startup:
+#if CONFIG_PAGE_OFFSET < LINGLOBAL_BASE
+ ! In case GCOn has just been turned on we need to fence any writes that
+ ! the boot thread might have performed prior to coherency taking effect.
+ MOVT D0Re0,#HI(LINSYSEVENT_WR_ATOMIC_UNLOCK)
+ MOV D1Re0,#0
+ SETD [D0Re0], D1Re0
+#endif
MOVT A0StP,#HI(_secondary_data_stack)
ADD A0StP,A0StP,#LO(_secondary_data_stack)
GETD A0StP,[A0StP]
diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c
index 87707efeb0a..5385dd1216b 100644
--- a/arch/metag/kernel/irq.c
+++ b/arch/metag/kernel/irq.c
@@ -25,7 +25,7 @@ static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
#endif
-struct irq_domain *root_domain;
+static struct irq_domain *root_domain;
static unsigned int startup_meta_irq(struct irq_data *data)
{
@@ -159,44 +159,30 @@ void irq_ctx_exit(int cpu)
extern asmlinkage void __do_softirq(void);
-asmlinkage void do_softirq(void)
+void do_softirq_own_stack(void)
{
- unsigned long flags;
struct thread_info *curctx;
union irq_ctx *irqctx;
u32 *isp;
- if (in_interrupt())
- return;
-
- local_irq_save(flags);
-
- if (local_softirq_pending()) {
- curctx = current_thread_info();
- irqctx = softirq_ctx[smp_processor_id()];
- irqctx->tinfo.task = curctx->task;
-
- /* build the stack frame on the softirq stack */
- isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info));
-
- asm volatile (
- "MOV D0.5,%0\n"
- "SWAP A0StP,D0.5\n"
- "CALLR D1RtP,___do_softirq\n"
- "MOV A0StP,D0.5\n"
- :
- : "r" (isp)
- : "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4",
- "D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP",
- "D0.5"
- );
- /*
- * Shouldn't happen, we returned above if in_interrupt():
- */
- WARN_ON_ONCE(softirq_count());
- }
-
- local_irq_restore(flags);
+ curctx = current_thread_info();
+ irqctx = softirq_ctx[smp_processor_id()];
+ irqctx->tinfo.task = curctx->task;
+
+ /* build the stack frame on the softirq stack */
+ isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info));
+
+ asm volatile (
+ "MOV D0.5,%0\n"
+ "SWAP A0StP,D0.5\n"
+ "CALLR D1RtP,___do_softirq\n"
+ "MOV A0StP,D0.5\n"
+ :
+ : "r" (isp)
+ : "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4",
+ "D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP",
+ "D0.5"
+ );
}
#endif
@@ -275,17 +261,6 @@ int __init arch_probe_nr_irqs(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
-
- raw_spin_lock_irq(&desc->lock);
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irq(&desc->lock);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -294,10 +269,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
- struct irq_desc *desc;
- for_each_irq_desc(i, desc) {
- struct irq_data *data = irq_desc_get_irq_data(desc);
+ for_each_active_irq(i) {
+ struct irq_data *data = irq_get_irq_data(i);
unsigned int newcpu;
if (irqd_is_per_cpu(data))
@@ -313,11 +287,8 @@ void migrate_irqs(void)
i, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, i, newcpu);
+ irq_set_affinity(i, data->affinity);
}
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/metag/kernel/kick.c b/arch/metag/kernel/kick.c
index 50fcbec98cd..beb37762132 100644
--- a/arch/metag/kernel/kick.c
+++ b/arch/metag/kernel/kick.c
@@ -26,6 +26,8 @@
* pass it as an argument.
*/
#include <linux/export.h>
+#include <linux/hardirq.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/types.h>
@@ -66,6 +68,7 @@ EXPORT_SYMBOL(kick_unregister_func);
TBIRES
kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
{
+ struct pt_regs *old_regs;
struct kick_irq_handler *kh;
struct list_head *lh;
int handled = 0;
@@ -79,6 +82,9 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
trace_hardirqs_off();
+ old_regs = set_irq_regs((struct pt_regs *)State.Sig.pCtx);
+ irq_enter();
+
/*
* There is no need to disable interrupts here because we
* can't nest KICK interrupts in a KICK interrupt handler.
@@ -97,5 +103,8 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
WARN_ON(!handled);
+ irq_exit();
+ set_irq_regs(old_regs);
+
return tail_end(ret);
}
diff --git a/arch/metag/kernel/metag_ksyms.c b/arch/metag/kernel/metag_ksyms.c
index ec872ef14eb..215c94ad63a 100644
--- a/arch/metag/kernel/metag_ksyms.c
+++ b/arch/metag/kernel/metag_ksyms.c
@@ -1,5 +1,7 @@
#include <linux/export.h>
+#include <linux/types.h>
+#include <asm/checksum.h>
#include <asm/div64.h>
#include <asm/ftrace.h>
#include <asm/page.h>
@@ -15,6 +17,9 @@ EXPORT_SYMBOL(max_pfn);
EXPORT_SYMBOL(min_low_pfn);
#endif
+/* Network checksum functions */
+EXPORT_SYMBOL(csum_partial);
+
/* TBI symbols */
EXPORT_SYMBOL(__TBI);
EXPORT_SYMBOL(__TBIFindSeg);
diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a876d5ff389..5cc4d4dcf3c 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -22,9 +22,9 @@
#include <linux/slab.h>
#include <asm/core_reg.h>
-#include <asm/hwthread.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/processor.h>
#include "perf_event.h"
@@ -40,10 +40,10 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
/* PMU admin */
const char *perf_pmu_name(void)
{
- if (metag_pmu)
- return metag_pmu->pmu.name;
+ if (!metag_pmu)
+ return NULL;
- return NULL;
+ return metag_pmu->name;
}
EXPORT_SYMBOL_GPL(perf_pmu_name);
@@ -171,6 +171,7 @@ static int metag_pmu_event_init(struct perf_event *event)
switch (event->attr.type) {
case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE:
+ case PERF_TYPE_RAW:
err = _hw_perf_event_init(event);
break;
@@ -211,9 +212,10 @@ again:
/*
* Calculate the delta and add it to the counter.
*/
- delta = new_raw_count - prev_raw_count;
+ delta = (new_raw_count - prev_raw_count) & MAX_PERIOD;
local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
}
int metag_pmu_event_set_period(struct perf_event *event,
@@ -223,6 +225,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
s64 period = hwc->sample_period;
int ret = 0;
+ /* The period may have been changed */
+ if (unlikely(period != hwc->last_period))
+ left += period - hwc->last_period;
+
if (unlikely(left <= -period)) {
left = period;
local64_set(&hwc->period_left, left);
@@ -240,8 +246,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
if (left > (s64)metag_pmu->max_period)
left = metag_pmu->max_period;
- if (metag_pmu->write)
- metag_pmu->write(idx, (u64)(-left) & MAX_PERIOD);
+ if (metag_pmu->write) {
+ local64_set(&hwc->prev_count, -(s32)left);
+ metag_pmu->write(idx, -left & MAX_PERIOD);
+ }
perf_event_update_userpage(event);
@@ -549,6 +557,10 @@ static int _hw_perf_event_init(struct perf_event *event)
if (err)
return err;
break;
+
+ case PERF_TYPE_RAW:
+ mapping = attr->config;
+ break;
}
/* Return early if the event is unsupported */
@@ -610,15 +622,13 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
WARN_ONCE((config != 0x100),
"invalid configuration (%d) for counter (%d)\n",
config, idx);
-
- /* Reset the cycle count */
- __core_reg_set(TXTACTCYC, 0);
+ local64_set(&event->prev_count, __core_reg_get(TXTACTCYC));
goto unlock;
}
/* Check for a core internal or performance channel event. */
if (tmp) {
- void *perf_addr = (void *)PERF_COUNT(idx);
+ void *perf_addr;
/*
* Anything other than a cycle count will write the low-
@@ -632,9 +642,14 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
case 0xf0:
perf_addr = (void *)PERF_CHAN(idx);
break;
+
+ default:
+ perf_addr = NULL;
+ break;
}
- metag_out32((tmp & 0x0f), perf_addr);
+ if (perf_addr)
+ metag_out32((config & 0x0f), perf_addr);
/*
* Now we use the high nibble as the performance event to
@@ -643,13 +658,21 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
config = tmp >> 4;
}
- /*
- * Enabled counters start from 0. Early cores clear the count on
- * write but newer cores don't, so we make sure that the count is
- * set to 0.
- */
tmp = ((config & 0xf) << 28) |
- ((1 << 24) << cpu_2_hwthread_id[get_cpu()]);
+ ((1 << 24) << hard_processor_id());
+ if (metag_pmu->max_period)
+ /*
+ * Cores supporting overflow interrupts may have had the counter
+ * set to a specific value that needs preserving.
+ */
+ tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff;
+ else
+ /*
+ * Older cores reset the counter on write, so prev_count needs
+ * resetting too so we can calculate a correct delta.
+ */
+ local64_set(&event->prev_count, 0);
+
metag_out32(tmp, PERF_COUNT(idx));
unlock:
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
@@ -693,9 +716,8 @@ static u64 metag_pmu_read_counter(int idx)
{
u32 tmp = 0;
- /* The act of reading the cycle counter also clears it */
if (METAG_INST_COUNTER == idx) {
- __core_reg_swap(TXTACTCYC, tmp);
+ tmp = __core_reg_get(TXTACTCYC);
goto out;
}
@@ -764,10 +786,16 @@ static irqreturn_t metag_pmu_counter_overflow(int irq, void *dev)
/*
* Enable the counter again once core overflow processing has
- * completed.
+ * completed. Note the counter value may have been modified while it was
+ * inactive to set it up ready for the next interrupt.
*/
- if (!perf_event_overflow(event, &sampledata, regs))
+ if (!perf_event_overflow(event, &sampledata, regs)) {
+ __global_lock2(flags);
+ counter = (counter & 0xff000000) |
+ (metag_in32(PERF_COUNT(idx)) & 0x00ffffff);
metag_out32(counter, PERF_COUNT(idx));
+ __global_unlock2(flags);
+ }
return IRQ_HANDLED;
}
@@ -785,8 +813,8 @@ static struct metag_pmu _metag_pmu = {
};
/* PMU CPU hotplug notifier */
-static int __cpuinit metag_pmu_cpu_notify(struct notifier_block *b,
- unsigned long action, void *hcpu)
+static int metag_pmu_cpu_notify(struct notifier_block *b, unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned int)hcpu;
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
@@ -800,7 +828,7 @@ static int __cpuinit metag_pmu_cpu_notify(struct notifier_block *b,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata metag_pmu_notifier = {
+static struct notifier_block metag_pmu_notifier = {
.notifier_call = metag_pmu_cpu_notify,
};
@@ -830,7 +858,7 @@ static int __init init_hw_perf_events(void)
metag_pmu->max_period = 0;
}
- metag_pmu->name = "Meta 2";
+ metag_pmu->name = "meta2";
metag_pmu->version = version;
metag_pmu->pmu = pmu;
}
@@ -854,7 +882,7 @@ static int __init init_hw_perf_events(void)
}
register_cpu_notifier(&metag_pmu_notifier);
- ret = perf_pmu_register(&pmu, (char *)metag_pmu->name, PERF_TYPE_RAW);
+ ret = perf_pmu_register(&pmu, metag_pmu->name, PERF_TYPE_RAW);
out:
return ret;
}
diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c
index c6efe62e5b7..483dff986a2 100644
--- a/arch/metag/kernel/process.c
+++ b/arch/metag/kernel/process.c
@@ -22,6 +22,7 @@
#include <linux/pm.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/smp.h>
#include <asm/core_reg.h>
#include <asm/user_gateway.h>
#include <asm/tcm.h>
@@ -31,7 +32,7 @@
/*
* Wait for the next interrupt and enable local interrupts
*/
-static inline void arch_idle(void)
+void arch_cpu_idle(void)
{
int tmp;
@@ -59,36 +60,12 @@ static inline void arch_idle(void)
: "r" (get_trigger_mask()));
}
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched()) {
- /*
- * We need to disable interrupts here to ensure we don't
- * miss a wakeup call.
- */
- local_irq_disable();
- if (!need_resched()) {
#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
-#endif
- arch_idle();
- } else {
- local_irq_enable();
- }
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
}
+#endif
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -152,6 +129,8 @@ void show_regs(struct pt_regs *regs)
"D1.7 "
};
+ show_regs_print_info(KERN_INFO);
+
pr_info(" pt_regs @ %p\n", regs);
pr_info(" SaveMask = 0x%04hx\n", regs->ctx.SaveMask);
pr_info(" Flags = 0x%04hx (%c%c%c%c)\n", regs->ctx.Flags,
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 47a8828615a..7563628822b 100644
--- a/arch/metag/kernel/ptrace.c
+++ b/arch/metag/kernel/ptrace.c
@@ -288,10 +288,36 @@ static int metag_rp_state_set(struct task_struct *target,
return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf);
}
+static int metag_tls_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ void __user *tls = target->thread.tls_ptr;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+}
+
+static int metag_tls_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ void __user *tls;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+ if (ret)
+ return ret;
+
+ target->thread.tls_ptr = tls;
+ return ret;
+}
+
enum metag_regset {
REGSET_GENERAL,
REGSET_CBUF,
REGSET_READPIPE,
+ REGSET_TLS,
};
static const struct user_regset metag_regsets[] = {
@@ -319,6 +345,14 @@ static const struct user_regset metag_regsets[] = {
.get = metag_rp_state_get,
.set = metag_rp_state_set,
},
+ [REGSET_TLS] = {
+ .core_note_type = NT_METAG_TLS,
+ .n = 1,
+ .size = sizeof(void *),
+ .align = sizeof(void *),
+ .get = metag_tls_get,
+ .set = metag_tls_set,
+ },
};
static const struct user_regset_view user_metag_view = {
diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c
index 879246170ae..31cf53d0eba 100644
--- a/arch/metag/kernel/setup.c
+++ b/arch/metag/kernel/setup.c
@@ -20,6 +20,7 @@
#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <linux/pfn.h>
#include <linux/root_dev.h>
#include <linux/sched.h>
@@ -41,7 +42,6 @@
#include <asm/mmu.h>
#include <asm/mmzone.h>
#include <asm/processor.h>
-#include <asm/prom.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/traps.h>
@@ -105,16 +105,12 @@
extern char _heap_start[];
-#ifdef CONFIG_METAG_BUILTIN_DTB
-extern u32 __dtb_start[];
-#endif
-
#ifdef CONFIG_DA_CONSOLE
/* Our early channel based console driver */
extern struct console dash_console;
#endif
-struct machine_desc *machine_desc __initdata;
+const struct machine_desc *machine_desc __initdata;
/*
* Map a Linux CPU number to a hardware thread ID
@@ -124,6 +120,7 @@ struct machine_desc *machine_desc __initdata;
u8 cpu_2_hwthread_id[NR_CPUS] __read_mostly = {
[0 ... NR_CPUS-1] = BAD_HWTHREAD_ID
};
+EXPORT_SYMBOL_GPL(cpu_2_hwthread_id);
/*
* Map a hardware thread ID to a Linux CPU number
@@ -300,13 +297,9 @@ void __init setup_arch(char **cmdline_p)
* rather than the version from the bootloader. This makes call
* stacks easier to understand and may allow us to unmap the
* bootloader at some point.
- *
- * We need to keep the LWK handler that TBI installed in order to
- * be able to do inter-thread comms.
*/
for (i = 0; i <= TBID_SIGNUM_MAX; i++)
- if (i != TBID_SIGNUM_LWK)
- _pTBI->fnSigs[i] = __TBIUnExpXXX;
+ _pTBI->fnSigs[i] = __TBIUnExpXXX;
/* A Meta requirement is that the kernel is loaded (virtually)
* at the PAGE_OFFSET.
@@ -406,9 +399,7 @@ void __init setup_arch(char **cmdline_p)
cpu_2_hwthread_id[smp_processor_id()] = hard_processor_id();
hwthread_id_2_cpu[hard_processor_id()] = smp_processor_id();
- /* Copy device tree blob into non-init memory before unflattening */
- copy_fdt();
- unflatten_device_tree();
+ unflatten_and_copy_device_tree();
#ifdef CONFIG_SMP
smp_init_cpus();
@@ -423,6 +414,9 @@ static int __init customize_machine(void)
/* customizes platform devices, or adds new ones */
if (machine_desc->init_machine)
machine_desc->init_machine();
+ else
+ of_platform_populate(NULL, of_default_bus_match_table, NULL,
+ NULL);
return 0;
}
arch_initcall(customize_machine);
@@ -586,20 +580,20 @@ PTBI pTBI_get(unsigned int cpu)
EXPORT_SYMBOL(pTBI_get);
#if defined(CONFIG_METAG_DSP) && defined(CONFIG_METAG_FPU)
-char capabilites[] = "dsp fpu";
+static char capabilities[] = "dsp fpu";
#elif defined(CONFIG_METAG_DSP)
-char capabilites[] = "dsp";
+static char capabilities[] = "dsp";
#elif defined(CONFIG_METAG_FPU)
-char capabilites[] = "fpu";
+static char capabilities[] = "fpu";
#else
-char capabilites[] = "";
+static char capabilities[] = "";
#endif
static struct ctl_table caps_kern_table[] = {
{
.procname = "capabilities",
- .data = capabilites,
- .maxlen = sizeof(capabilites),
+ .data = capabilities,
+ .maxlen = sizeof(capabilities),
.mode = 0444,
.proc_handler = proc_dostring,
},
diff --git a/arch/metag/kernel/signal.c b/arch/metag/kernel/signal.c
index 3be61cf0b14..b9e4a82d2bd 100644
--- a/arch/metag/kernel/signal.c
+++ b/arch/metag/kernel/signal.c
@@ -152,18 +152,18 @@ static void __user *get_sigframe(struct k_sigaction *ka, unsigned long sp,
return (void __user *)sp;
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- int err = -EFAULT;
+ int err;
unsigned long code;
- frame = get_sigframe(ka, regs->REG_SP, sizeof(*frame));
+ frame = get_sigframe(&ksig->ka, regs->REG_SP, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto out;
+ return -EFAULT;
- err = copy_siginfo_to_user(&frame->info, info);
+ err = copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -174,7 +174,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto out;
+ return -EFAULT;
/* Set up to return from userspace. */
@@ -187,15 +187,15 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(code, (unsigned long __user *)(&frame->retcode[1]));
if (err)
- goto out;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->REG_RTP = (unsigned long) frame->retcode;
regs->REG_SP = (unsigned long) frame + sizeof(*frame);
- regs->REG_ARG1 = sig;
+ regs->REG_ARG1 = ksig->sig;
regs->REG_ARG2 = (unsigned long) &frame->info;
regs->REG_ARG3 = (unsigned long) &frame->uc;
- regs->REG_PC = (unsigned long) ka->sa.sa_handler;
+ regs->REG_PC = (unsigned long) ksig->ka.sa.sa_handler;
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08x pr=%08x\n",
current->comm, current->pid, frame, regs->REG_PC,
@@ -205,24 +205,19 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* effective cache flush - directed rather than 'full flush'.
*/
flush_cache_sigtramp(regs->REG_RTP, sizeof(frame->retcode));
-out:
- if (err) {
- force_sigsegv(sig, current);
- return -EFAULT;
- }
+
return 0;
}
-static void handle_signal(unsigned long sig, siginfo_t *info,
- struct k_sigaction *ka, struct pt_regs *regs)
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
+ int ret;
/* Set up the stack frame */
- if (setup_rt_frame(sig, ka, info, oldset, regs))
- return;
+ ret = setup_rt_frame(ksig, oldset, regs);
- signal_delivered(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP));
+ signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
}
/*
@@ -235,10 +230,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
static int do_signal(struct pt_regs *regs, int syscall)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
- struct k_sigaction ka;
- siginfo_t info;
- int signr;
int restart = 0;
+ struct ksignal ksig;
/*
* By the end of rt_sigreturn the context describes the point that the
@@ -275,7 +268,8 @@ static int do_signal(struct pt_regs *regs, int syscall)
* Get the signal to deliver. When running under ptrace, at this point
* the debugger may change all our registers ...
*/
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ get_signal(&ksig);
+
/*
* Depending on the signal settings we may need to revert the decision
* to restart the system call. But skip this if a debugger has chosen to
@@ -283,19 +277,19 @@ static int do_signal(struct pt_regs *regs, int syscall)
*/
if (regs->REG_PC != restart_addr)
restart = 0;
- if (signr > 0) {
+ if (ksig.sig > 0) {
if (unlikely(restart)) {
if (retval == -ERESTARTNOHAND
|| retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART))) {
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
regs->REG_RETVAL = -EINTR;
regs->REG_PC = continue_addr;
}
}
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, &ka, regs);
+ handle_signal(&ksig, regs);
return 0;
}
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index 4b6d1f14df3..f006d2276f4 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/atomic.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -28,6 +29,8 @@
#include <asm/cachepart.h>
#include <asm/core_reg.h>
#include <asm/cpu.h>
+#include <asm/global_lock.h>
+#include <asm/metag_mem.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -37,6 +40,9 @@
#include <asm/hwthread.h>
#include <asm/traps.h>
+#define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
+#define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
+
DECLARE_PER_CPU(PTBI, pTBI);
void *secondary_data_stack;
@@ -57,10 +63,12 @@ static DEFINE_PER_CPU(struct ipi_data, ipi_data) = {
static DEFINE_SPINLOCK(boot_lock);
+static DECLARE_COMPLETION(cpu_running);
+
/*
* "thread" is assumed to be a valid Meta hardware thread ID.
*/
-int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
+static int boot_secondary(unsigned int thread, struct task_struct *idle)
{
u32 val;
@@ -99,7 +107,113 @@ int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
return 0;
}
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+/**
+ * describe_cachepart_change: describe a change to cache partitions.
+ * @thread: Hardware thread number.
+ * @label: Label of cache type, e.g. "dcache" or "icache".
+ * @sz: Total size of the cache.
+ * @old: Old cache partition configuration (*CPART* register).
+ * @new: New cache partition configuration (*CPART* register).
+ *
+ * If the cache partition has changed, prints a message to the log describing
+ * those changes.
+ */
+static void describe_cachepart_change(unsigned int thread, const char *label,
+ unsigned int sz, unsigned int old,
+ unsigned int new)
+{
+ unsigned int lor1, land1, gor1, gand1;
+ unsigned int lor2, land2, gor2, gand2;
+ unsigned int diff = old ^ new;
+
+ if (!diff)
+ return;
+
+ pr_info("Thread %d: %s partition changed:", thread, label);
+ if (diff & (SYSC_xCPARTL_OR_BITS | SYSC_xCPARTL_AND_BITS)) {
+ lor1 = (old & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
+ lor2 = (new & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
+ land1 = (old & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+ land2 = (new & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+ pr_cont(" L:%#x+%#x->%#x+%#x",
+ (lor1 * sz) >> 4,
+ ((land1 + 1) * sz) >> 4,
+ (lor2 * sz) >> 4,
+ ((land2 + 1) * sz) >> 4);
+ }
+ if (diff & (SYSC_xCPARTG_OR_BITS | SYSC_xCPARTG_AND_BITS)) {
+ gor1 = (old & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
+ gor2 = (new & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
+ gand1 = (old & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+ gand2 = (new & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+ pr_cont(" G:%#x+%#x->%#x+%#x",
+ (gor1 * sz) >> 4,
+ ((gand1 + 1) * sz) >> 4,
+ (gor2 * sz) >> 4,
+ ((gand2 + 1) * sz) >> 4);
+ }
+ if (diff & SYSC_CWRMODE_BIT)
+ pr_cont(" %sWR",
+ (new & SYSC_CWRMODE_BIT) ? "+" : "-");
+ if (diff & SYSC_DCPART_GCON_BIT)
+ pr_cont(" %sGCOn",
+ (new & SYSC_DCPART_GCON_BIT) ? "+" : "-");
+ pr_cont("\n");
+}
+
+/**
+ * setup_smp_cache: ensure cache coherency for new SMP thread.
+ * @thread: New hardware thread number.
+ *
+ * Ensures that coherency is enabled and that the threads share the same cache
+ * partitions.
+ */
+static void setup_smp_cache(unsigned int thread)
+{
+ unsigned int this_thread, lflags;
+ unsigned int dcsz, dcpart_this, dcpart_old, dcpart_new;
+ unsigned int icsz, icpart_old, icpart_new;
+
+ /*
+ * Copy over the current thread's cache partition configuration to the
+ * new thread so that they share cache partitions.
+ */
+ __global_lock2(lflags);
+ this_thread = hard_processor_id();
+ /* Share dcache partition */
+ dcpart_this = metag_in32(SYSC_DCPART(this_thread));
+ dcpart_old = metag_in32(SYSC_DCPART(thread));
+ dcpart_new = dcpart_this;
+#if PAGE_OFFSET < LINGLOBAL_BASE
+ /*
+ * For the local data cache to be coherent the threads must also have
+ * GCOn enabled.
+ */
+ dcpart_new |= SYSC_DCPART_GCON_BIT;
+ metag_out32(dcpart_new, SYSC_DCPART(this_thread));
+#endif
+ metag_out32(dcpart_new, SYSC_DCPART(thread));
+ /* Share icache partition too */
+ icpart_new = metag_in32(SYSC_ICPART(this_thread));
+ icpart_old = metag_in32(SYSC_ICPART(thread));
+ metag_out32(icpart_new, SYSC_ICPART(thread));
+ __global_unlock2(lflags);
+
+ /*
+ * Log if the cache partitions were altered so the user is aware of any
+ * potential unintentional cache wastage.
+ */
+ dcsz = get_dcache_size();
+ icsz = get_dcache_size();
+ describe_cachepart_change(this_thread, "dcache", dcsz,
+ dcpart_this, dcpart_new);
+ describe_cachepart_change(thread, "dcache", dcsz,
+ dcpart_old, dcpart_new);
+ describe_cachepart_change(thread, "icache", icsz,
+ icpart_old, icpart_new);
+}
+
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
{
unsigned int thread = cpu_2_hwthread_id[cpu];
int ret;
@@ -108,6 +222,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
flush_tlb_all();
+ setup_smp_cache(thread);
+
/*
* Tell the secondary CPU where to find its idle thread's stack.
*/
@@ -120,20 +236,12 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
*/
ret = boot_secondary(thread, idle);
if (ret == 0) {
- unsigned long timeout;
-
/*
* CPU was successfully started, wait for it
* to come online or time out.
*/
- timeout = jiffies + HZ;
- while (time_before(jiffies, timeout)) {
- if (cpu_online(cpu))
- break;
-
- udelay(10);
- barrier();
- }
+ wait_for_completion_timeout(&cpu_running,
+ msecs_to_jiffies(1000));
if (!cpu_online(cpu))
ret = -EIO;
@@ -158,10 +266,9 @@ static DECLARE_COMPLETION(cpu_killed);
/*
* __cpu_disable runs on the processor to be shutdown.
*/
-int __cpuexit __cpu_disable(void)
+int __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
- struct task_struct *p;
/*
* Take this CPU offline. Once we clear this, we can't return,
@@ -181,12 +288,7 @@ int __cpuexit __cpu_disable(void)
flush_cache_all();
local_flush_tlb_all();
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (p->mm)
- cpumask_clear_cpu(cpu, mm_cpumask(p->mm));
- }
- read_unlock(&tasklist_lock);
+ clear_tasks_mm_cpumask(cpu);
return 0;
}
@@ -195,7 +297,7 @@ int __cpuexit __cpu_disable(void)
* called on the thread which is asking for a CPU to be shutdown -
* waits until shutdown has completed, or it is timed out.
*/
-void __cpuexit __cpu_die(unsigned int cpu)
+void __cpu_die(unsigned int cpu)
{
if (!wait_for_completion_timeout(&cpu_killed, msecs_to_jiffies(1)))
pr_err("CPU%u: unable to kill\n", cpu);
@@ -207,7 +309,7 @@ void __cpuexit __cpu_die(unsigned int cpu)
* Note that we do not return from this function. If this cpu is
* brought online again it will need to run secondary_startup().
*/
-void __cpuexit cpu_die(void)
+void cpu_die(void)
{
local_irq_disable();
idle_task_exit();
@@ -222,7 +324,7 @@ void __cpuexit cpu_die(void)
* Called by both boot and secondaries to move global data into
* per-processor storage.
*/
-void __cpuinit smp_store_cpu_info(unsigned int cpuid)
+void smp_store_cpu_info(unsigned int cpuid)
{
struct cpuinfo_metag *cpu_info = &per_cpu(cpu_data, cpuid);
@@ -270,12 +372,7 @@ asmlinkage void secondary_start_kernel(void)
setup_priv();
- /*
- * Enable local interrupts.
- */
- tbi_startup_interrupt(TBID_SIGNUM_TRT);
notify_cpu_starting(cpu);
- local_irq_enable();
pr_info("CPU%u (thread %u): Booted secondary processor\n",
cpu, cpu_2_hwthread_id[cpu]);
@@ -287,17 +384,18 @@ asmlinkage void secondary_start_kernel(void)
* OK, now it's safe to let the boot CPU continue
*/
set_cpu_online(cpu, true);
+ complete(&cpu_running);
/*
- * Check for cache aliasing.
- * Preemption is disabled
+ * Enable local interrupts.
*/
- check_for_cache_aliasing(cpu);
+ tbi_startup_interrupt(TBID_SIGNUM_TRT);
+ local_irq_enable();
/*
* OK, it's off to the idle thread for us
*/
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_cpus_done(unsigned int max_cpus)
@@ -393,7 +491,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
void arch_send_call_function_single_ipi(int cpu)
{
- send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+ send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
}
void show_ipi_list(struct seq_file *p)
@@ -419,11 +517,10 @@ static DEFINE_SPINLOCK(stop_lock);
*
* Bit 0 - Inter-processor function call
*/
-static int do_IPI(struct pt_regs *regs)
+static int do_IPI(void)
{
unsigned int cpu = smp_processor_id();
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
- struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long msgs, nextmsg;
int handled = 0;
@@ -448,10 +545,6 @@ static int do_IPI(struct pt_regs *regs)
generic_smp_call_function_interrupt();
break;
- case IPI_CALL_FUNC_SINGLE:
- generic_smp_call_function_single_interrupt();
- break;
-
default:
pr_crit("CPU%u: Unknown IPI message 0x%lx\n",
cpu, nextmsg);
@@ -459,8 +552,6 @@ static int do_IPI(struct pt_regs *regs)
}
}
- set_irq_regs(old_regs);
-
return handled;
}
@@ -526,7 +617,7 @@ static void kick_raise_softirq(cpumask_t callmap, unsigned int irq)
static TBIRES ipi_handler(TBIRES State, int SigNum, int Triggers,
int Inst, PTBI pTBI, int *handled)
{
- *handled = do_IPI((struct pt_regs *)State.Sig.pCtx);
+ *handled = do_IPI();
return State;
}
diff --git a/arch/metag/kernel/time.c b/arch/metag/kernel/time.c
index 17dc10733b2..f1c8c53dace 100644
--- a/arch/metag/kernel/time.c
+++ b/arch/metag/kernel/time.c
@@ -5,11 +5,21 @@
*
*/
-#include <linux/init.h>
-
#include <clocksource/metag_generic.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <asm/clock.h>
void __init time_init(void)
{
+#ifdef CONFIG_COMMON_CLK
+ /* Init clocks from device tree */
+ of_clk_init(NULL);
+#endif
+
+ /* Init meta clocks, particularly the core clock */
+ init_metag_clocks();
+
+ /* Set up the timer clock sources */
metag_generic_timer_init();
}
diff --git a/arch/metag/kernel/topology.c b/arch/metag/kernel/topology.c
index bec3dec4922..4ba595701f7 100644
--- a/arch/metag/kernel/topology.c
+++ b/arch/metag/kernel/topology.c
@@ -19,6 +19,7 @@
DEFINE_PER_CPU(struct cpuinfo_metag, cpu_data);
cpumask_t cpu_core_map[NR_CPUS];
+EXPORT_SYMBOL(cpu_core_map);
static cpumask_t cpu_coregroup_map(unsigned int cpu)
{
diff --git a/arch/metag/kernel/traps.c b/arch/metag/kernel/traps.c
index 8961f247b50..17b2e2e38d5 100644
--- a/arch/metag/kernel/traps.c
+++ b/arch/metag/kernel/traps.c
@@ -33,6 +33,7 @@
#include <asm/siginfo.h>
#include <asm/traps.h>
#include <asm/hwthread.h>
+#include <asm/setup.h>
#include <asm/switch.h>
#include <asm/user_gateway.h>
#include <asm/syscall.h>
@@ -87,8 +88,8 @@ const char *trap_name(int trapno)
static DEFINE_SPINLOCK(die_lock);
-void die(const char *str, struct pt_regs *regs, long err,
- unsigned long addr)
+void __noreturn die(const char *str, struct pt_regs *regs,
+ long err, unsigned long addr)
{
static int die_counter;
@@ -811,15 +812,14 @@ static void set_trigger_mask(unsigned int mask)
}
#endif
-void __cpuinit per_cpu_trap_init(unsigned long cpu)
+void per_cpu_trap_init(unsigned long cpu)
{
TBIRES int_context;
unsigned int thread = cpu_2_hwthread_id[cpu];
set_trigger_mask(TBI_INTS_INIT(thread) | /* interrupts */
TBI_TRIG_BIT(TBID_SIGNUM_LWK) | /* low level kick */
- TBI_TRIG_BIT(TBID_SIGNUM_SW1) |
- TBI_TRIG_BIT(TBID_SIGNUM_SWS));
+ TBI_TRIG_BIT(TBID_SIGNUM_SW1));
/* non-priv - use current stack */
int_context.Sig.pCtx = NULL;
@@ -841,7 +841,7 @@ void __init trap_init(void)
_pTBI->fnSigs[TBID_SIGNUM_SW1] = switch1_handler;
_pTBI->fnSigs[TBID_SIGNUM_SW2] = switchx_handler;
_pTBI->fnSigs[TBID_SIGNUM_SW3] = switchx_handler;
- _pTBI->fnSigs[TBID_SIGNUM_SWK] = kick_handler;
+ _pTBI->fnSigs[TBID_SIGNUM_LWK] = kick_handler;
#ifdef CONFIG_METAG_META21
_pTBI->fnSigs[TBID_SIGNUM_DFR] = __TBIHandleDFR;
@@ -987,9 +987,3 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_trace(tsk, sp, NULL);
}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/metag/lib/checksum.c b/arch/metag/lib/checksum.c
index 44d2e191356..5d6a98a05e9 100644
--- a/arch/metag/lib/checksum.c
+++ b/arch/metag/lib/checksum.c
@@ -124,7 +124,6 @@ __wsum csum_partial(const void *buff, int len, __wsum wsum)
result += 1;
return (__force __wsum)result;
}
-EXPORT_SYMBOL(csum_partial);
/*
* this routine is used for miscellaneous IP-like checksums, mainly
diff --git a/arch/metag/mm/Kconfig b/arch/metag/mm/Kconfig
index 975f2f4e3ec..03fb8f1555a 100644
--- a/arch/metag/mm/Kconfig
+++ b/arch/metag/mm/Kconfig
@@ -93,14 +93,6 @@ config ARCH_SPARSEMEM_ENABLE
config ARCH_SPARSEMEM_DEFAULT
def_bool y
-config MAX_ACTIVE_REGIONS
- int
- default "2" if SPARSEMEM
- default "1"
-
-config ARCH_POPULATES_NODE_MAP
- def_bool y
-
config ARCH_SELECT_MEMORY_MODEL
def_bool y
diff --git a/arch/metag/mm/cache.c b/arch/metag/mm/cache.c
index b5d3b2e7c16..a62285284ab 100644
--- a/arch/metag/mm/cache.c
+++ b/arch/metag/mm/cache.c
@@ -45,7 +45,7 @@ static volatile u32 lnkget_testdata[16] __initdata __aligned(64);
#define LNKGET_CONSTANT 0xdeadbeef
-void __init metag_lnkget_probe(void)
+static void __init metag_lnkget_probe(void)
{
int temp;
long flags;
diff --git a/arch/metag/mm/fault.c b/arch/metag/mm/fault.c
index 2c75bf7357c..332680e5ebf 100644
--- a/arch/metag/mm/fault.c
+++ b/arch/metag/mm/fault.c
@@ -53,8 +53,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
struct vm_area_struct *vma, *prev_vma;
siginfo_t info;
int fault;
- unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
- (write_access ? FAULT_FLAG_WRITE : 0);
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
tsk = current;
@@ -109,6 +108,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
if (in_atomic() || !mm)
goto no_context;
+ if (user_mode(regs))
+ flags |= FAULT_FLAG_USER;
retry:
down_read(&mm->mmap_sem);
@@ -121,6 +122,7 @@ good_area:
if (write_access) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
+ flags |= FAULT_FLAG_WRITE;
} else {
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
@@ -224,8 +226,10 @@ do_sigbus:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (user_mode(regs))
- do_group_exit(SIGKILL);
+ if (user_mode(regs)) {
+ pagefault_out_of_memory();
+ return 1;
+ }
no_context:
/* Are we prepared to handle this kernel fault? */
diff --git a/arch/metag/mm/init.c b/arch/metag/mm/init.c
index 504a398d5f8..11fa51c8961 100644
--- a/arch/metag/mm/init.c
+++ b/arch/metag/mm/init.c
@@ -12,7 +12,6 @@
#include <linux/percpu.h>
#include <linux/memblock.h>
#include <linux/initrd.h>
-#include <linux/of_fdt.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -149,7 +148,7 @@ static void __init bootmem_init_one_node(unsigned int nid)
if (!p->node_spanned_pages)
return;
- end_pfn = p->node_start_pfn + p->node_spanned_pages;
+ end_pfn = pgdat_end_pfn(p);
#ifdef CONFIG_HIGHMEM
if (end_pfn > max_low_pfn)
end_pfn = max_low_pfn;
@@ -205,7 +204,8 @@ static void __init do_init_bootmem(void)
start_pfn = memblock_region_memory_base_pfn(reg);
end_pfn = memblock_region_memory_end_pfn(reg);
memblock_set_node(PFN_PHYS(start_pfn),
- PFN_PHYS(end_pfn - start_pfn), 0);
+ PFN_PHYS(end_pfn - start_pfn),
+ &memblock.memory, 0);
}
/* All of system RAM sits in node 0 for the non-NUMA case */
@@ -376,76 +376,32 @@ void __init paging_init(unsigned long mem_end)
void __init mem_init(void)
{
- int nid;
-
#ifdef CONFIG_HIGHMEM
unsigned long tmp;
- for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
- struct page *page = pfn_to_page(tmp);
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
- }
- totalram_pages += totalhigh_pages;
- num_physpages += totalhigh_pages;
-#endif /* CONFIG_HIGHMEM */
-
- for_each_online_node(nid) {
- pg_data_t *pgdat = NODE_DATA(nid);
- unsigned long node_pages = 0;
-
- num_physpages += pgdat->node_present_pages;
-
- if (pgdat->node_spanned_pages)
- node_pages = free_all_bootmem_node(pgdat);
-
- totalram_pages += node_pages;
- }
- pr_info("Memory: %luk/%luk available\n",
- (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
- num_physpages << (PAGE_SHIFT - 10));
+ /*
+ * Explicitly reset zone->managed_pages because highmem pages are
+ * freed before calling free_all_bootmem();
+ */
+ reset_all_zones_managed_pages();
+ for (tmp = highstart_pfn; tmp < highend_pfn; tmp++)
+ free_highmem_page(pfn_to_page(tmp));
+#endif /* CONFIG_HIGHMEM */
+ free_all_bootmem();
+ mem_init_print_info(NULL);
show_mem(0);
-
- return;
-}
-
-static void free_init_pages(char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
-
- for (addr = begin; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
- }
- pr_info("Freeing %s: %luk freed\n", what, (end - begin) >> 10);
}
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)(&__init_begin),
- (unsigned long)(&__init_end));
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- end = end & PAGE_MASK;
- free_init_pages("initrd memory", start, end);
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "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/metag/mm/numa.c b/arch/metag/mm/numa.c
index 9ae578c9b62..67b46c29507 100644
--- a/arch/metag/mm/numa.c
+++ b/arch/metag/mm/numa.c
@@ -34,7 +34,7 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
unsigned long pgdat_paddr;
/* Don't allow bogus node assignment */
- BUG_ON(nid > MAX_NUMNODES || nid <= 0);
+ BUG_ON(nid >= MAX_NUMNODES || nid <= 0);
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
@@ -42,7 +42,8 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
memblock_add(start, end - start);
memblock_set_node(PFN_PHYS(start_pfn),
- PFN_PHYS(end_pfn - start_pfn), nid);
+ PFN_PHYS(end_pfn - start_pfn),
+ &memblock.memory, nid);
/* Node-local pgdat */
pgdat_paddr = memblock_alloc_base(sizeof(struct pglist_data),
diff --git a/arch/metag/oprofile/Makefile b/arch/metag/oprofile/Makefile
new file mode 100644
index 00000000000..c9639d4734d
--- /dev/null
+++ b/arch/metag/oprofile/Makefile
@@ -0,0 +1,17 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+oprofile-core-y += buffer_sync.o
+oprofile-core-y += cpu_buffer.o
+oprofile-core-y += event_buffer.o
+oprofile-core-y += oprof.o
+oprofile-core-y += oprofile_files.o
+oprofile-core-y += oprofile_stats.o
+oprofile-core-y += oprofilefs.o
+oprofile-core-y += timer_int.o
+oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o
+
+oprofile-y += backtrace.o
+oprofile-y += common.o
+oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y))
+
+ccflags-y += -Werror
diff --git a/arch/metag/oprofile/backtrace.c b/arch/metag/oprofile/backtrace.c
new file mode 100644
index 00000000000..7cc3f37cb40
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010-2013 Imagination Technologies Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/stacktrace.h>
+
+#include "backtrace.h"
+
+static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth)
+{
+ while (depth-- && access_ok(VERIFY_READ, fp, 8)) {
+ unsigned long addr;
+ unsigned long __user *fpnew;
+ if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr)))
+ break;
+ addr -= 4;
+
+ oprofile_add_trace(addr);
+
+ /* stack grows up, so frame pointers must decrease */
+ if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew)))
+ break;
+ if (fpnew >= fp)
+ break;
+ fp = fpnew;
+ }
+}
+
+static int kernel_backtrace_frame(struct stackframe *frame, void *data)
+{
+ unsigned int *depth = data;
+
+ oprofile_add_trace(frame->pc);
+
+ /* decrement depth and stop if we reach 0 */
+ if ((*depth)-- == 0)
+ return 1;
+
+ /* otherwise onto the next frame */
+ return 0;
+}
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+ if (user_mode(regs)) {
+ unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0;
+ user_backtrace_fp((unsigned long __user __force *)fp, depth);
+ } else {
+ struct stackframe frame;
+ frame.fp = regs->ctx.AX[1].U0; /* A0FrP */
+ frame.sp = user_stack_pointer(regs); /* A0StP */
+ frame.lr = 0; /* from stack */
+ frame.pc = regs->ctx.CurrPC; /* PC */
+ walk_stackframe(&frame, &kernel_backtrace_frame, &depth);
+ }
+}
diff --git a/arch/metag/oprofile/backtrace.h b/arch/metag/oprofile/backtrace.h
new file mode 100644
index 00000000000..c0fcc4265ab
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.h
@@ -0,0 +1,6 @@
+#ifndef _METAG_OPROFILE_BACKTRACE_H
+#define _METAG_OPROFILE_BACKTRACE_H
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+#endif
diff --git a/arch/metag/oprofile/common.c b/arch/metag/oprofile/common.c
new file mode 100644
index 00000000000..ba26152b3c0
--- /dev/null
+++ b/arch/metag/oprofile/common.c
@@ -0,0 +1,66 @@
+/*
+ * arch/metag/oprofile/common.c
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * Based on arch/sh/oprofile/common.c:
+ *
+ * Copyright (C) 2003 - 2010 Paul Mundt
+ *
+ * Based on arch/mips/oprofile/common.c:
+ *
+ * Copyright (C) 2004, 2005 Ralf Baechle
+ * Copyright (C) 2005 MIPS Technologies, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/oprofile.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "backtrace.h"
+
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *metag_pmu_op_name;
+
+char *op_name_from_perf_id(void)
+{
+ return metag_pmu_op_name;
+}
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+ ops->backtrace = metag_backtrace;
+
+ if (perf_num_counters() == 0)
+ return -ENODEV;
+
+ metag_pmu_op_name = kasprintf(GFP_KERNEL, "metag/%s",
+ perf_pmu_name());
+ if (unlikely(!metag_pmu_op_name))
+ return -ENOMEM;
+
+ return oprofile_perf_init(ops);
+}
+
+void oprofile_arch_exit(void)
+{
+ oprofile_perf_exit();
+ kfree(metag_pmu_op_name);
+}
+#else
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+ ops->backtrace = metag_backtrace;
+ /* fall back to timer interrupt PC sampling */
+ return -ENODEV;
+}
+void oprofile_arch_exit(void) {}
+#endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/metag/tbx/tbidefr.S b/arch/metag/tbx/tbidefr.S
index 3eb165ebf54..8f0902b22f7 100644
--- a/arch/metag/tbx/tbidefr.S
+++ b/arch/metag/tbx/tbidefr.S
@@ -20,7 +20,7 @@
/* D1Ar1:D0Ar2 -- State
* D0Ar3 -- SigNum
* D0Ar4 -- Triggers
- * D1Ar5 -- InstOrSWSId
+ * D1Ar5 -- Inst
* D0Ar6 -- pTBI (volatile)
*/
___TBIHandleDFR: