aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 13:09:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 13:09:39 -0400
commit87c1f0f8c9442c86cbb343b9324bef8312029d7d (patch)
tree47f97d468a83d2f13d08fe9603fc91e23cb60c8e /arch
parent165bc513f7ec54d3fa3660f5c851c4bbc533d577 (diff)
parent164c013858a2e89b450cd8021a8be896f9e05697 (diff)
Merge tag 'metag-for-v3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag
Pull arch/metag update from James Hogan: - Various fixes for the interrupting perf counter handling in metag's perf backend. - Add OProfile support based on perf. - Sets up cache partitions for SMP so bootloader doesn't have to. - Patch from Paul Bolle to remove ARCH_POPULATES_NODE_MAP again (touches microblaze too). - Add TLS pointer regset to metag ptrace api. - Add exported metag DSP extended context handling header <asm/ech.h>. - Increase defconfig log buffer size to 128KiB. - Various fixes, typos, missing exports. * tag 'metag-for-v3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag: metag: defconfigs: increase log buffer 8KiB => 128KiB metag: avoid unnecessary builtin dtb rebuilds metag: add exported <asm/ech.h> for extended context handling metag: export _metag_da_present and cpu_2_hwthread_id metag: ptrace: Implement NT_METAG_TLS memblock: Kill ARCH_POPULATES_NODE_MAP once more metag: cachepart: fix get_global_dcache_size() typo metag: cachepart: take into account small cache bits metag: smp: copy cache partition and enable GCOn metag: OProfile support metag: perf: prepare for use by oprofile metag: perf: don't reset TXTACTCYC metag: perf: use hard_processor_id() to get thread metag: perf: fix frequency sampling (dynamic period) metag: perf: add missing prev_count updates metag: perf: fixes for interrupting perf counters metag: perf: fix wrap handling in delta calculation metag: perf: fix core internal / perf channel mux
Diffstat (limited to 'arch')
-rw-r--r--arch/metag/Kconfig4
-rw-r--r--arch/metag/Makefile2
-rw-r--r--arch/metag/boot/dts/Makefile10
-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/include/asm/metag_mem.h3
-rw-r--r--arch/metag/include/uapi/asm/Kbuild1
-rw-r--r--arch/metag/include/uapi/asm/ech.h15
-rw-r--r--arch/metag/kernel/cachepart.c16
-rw-r--r--arch/metag/kernel/da.c2
-rw-r--r--arch/metag/kernel/head.S8
-rw-r--r--arch/metag/kernel/perf/perf_event.c74
-rw-r--r--arch/metag/kernel/ptrace.c34
-rw-r--r--arch/metag/kernel/setup.c1
-rw-r--r--arch/metag/kernel/smp.c115
-rw-r--r--arch/metag/mm/Kconfig3
-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/microblaze/Kconfig3
22 files changed, 406 insertions, 40 deletions
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index afc8973d1488..b06b41861aac 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -25,6 +25,7 @@ config METAG
25 select HAVE_MEMBLOCK 25 select HAVE_MEMBLOCK
26 select HAVE_MEMBLOCK_NODE_MAP 26 select HAVE_MEMBLOCK_NODE_MAP
27 select HAVE_MOD_ARCH_SPECIFIC 27 select HAVE_MOD_ARCH_SPECIFIC
28 select HAVE_OPROFILE
28 select HAVE_PERF_EVENTS 29 select HAVE_PERF_EVENTS
29 select HAVE_SYSCALL_TRACEPOINTS 30 select HAVE_SYSCALL_TRACEPOINTS
30 select IRQ_DOMAIN 31 select IRQ_DOMAIN
@@ -209,6 +210,9 @@ config METAG_PERFCOUNTER_IRQS
209 When disabled, Performance Counters information will be collected 210 When disabled, Performance Counters information will be collected
210 based on Timer Interrupt. 211 based on Timer Interrupt.
211 212
213config HW_PERF_EVENTS
214 def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS
215
212config METAG_DA 216config METAG_DA
213 bool "DA support" 217 bool "DA support"
214 help 218 help
diff --git a/arch/metag/Makefile b/arch/metag/Makefile
index 81bd6a1c7483..b566116b171b 100644
--- a/arch/metag/Makefile
+++ b/arch/metag/Makefile
@@ -49,6 +49,8 @@ core-y += arch/metag/mm/
49libs-y += arch/metag/lib/ 49libs-y += arch/metag/lib/
50libs-y += arch/metag/tbx/ 50libs-y += arch/metag/tbx/
51 51
52drivers-$(CONFIG_OPROFILE) += arch/metag/oprofile/
53
52boot := arch/metag/boot 54boot := arch/metag/boot
53 55
54boot_targets += uImage 56boot_targets += uImage
diff --git a/arch/metag/boot/dts/Makefile b/arch/metag/boot/dts/Makefile
index e0b5afd8bde8..dbd95217733a 100644
--- a/arch/metag/boot/dts/Makefile
+++ b/arch/metag/boot/dts/Makefile
@@ -4,13 +4,17 @@ dtb-y += skeleton.dtb
4builtindtb-y := skeleton 4builtindtb-y := skeleton
5 5
6ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"") 6ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"")
7 builtindtb-y := $(CONFIG_METAG_BUILTIN_DTB_NAME) 7 builtindtb-y := $(patsubst "%",%,$(CONFIG_METAG_BUILTIN_DTB_NAME))
8endif 8endif
9obj-$(CONFIG_METAG_BUILTIN_DTB) += $(patsubst "%",%,$(builtindtb-y)).dtb.o 9
10dtb-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb
11obj-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb.o
10 12
11targets += dtbs 13targets += dtbs
12targets += $(dtb-y) 14targets += $(dtb-y)
13 15
16.SECONDARY: $(obj)/$(builtindtb-y).dtb.S
17
14dtbs: $(addprefix $(obj)/, $(dtb-y)) 18dtbs: $(addprefix $(obj)/, $(dtb-y))
15 19
16clean-files += *.dtb 20clean-files += *.dtb *.dtb.S
diff --git a/arch/metag/configs/meta1_defconfig b/arch/metag/configs/meta1_defconfig
index c35a75e8ecfe..01cd67e4403d 100644
--- a/arch/metag/configs/meta1_defconfig
+++ b/arch/metag/configs/meta1_defconfig
@@ -1,6 +1,5 @@
1# CONFIG_LOCALVERSION_AUTO is not set 1# CONFIG_LOCALVERSION_AUTO is not set
2# CONFIG_SWAP is not set 2# CONFIG_SWAP is not set
3CONFIG_LOG_BUF_SHIFT=13
4CONFIG_SYSFS_DEPRECATED=y 3CONFIG_SYSFS_DEPRECATED=y
5CONFIG_SYSFS_DEPRECATED_V2=y 4CONFIG_SYSFS_DEPRECATED_V2=y
6CONFIG_KALLSYMS_ALL=y 5CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_defconfig b/arch/metag/configs/meta2_defconfig
index fb3148410183..643392ba7ed5 100644
--- a/arch/metag/configs/meta2_defconfig
+++ b/arch/metag/configs/meta2_defconfig
@@ -1,7 +1,6 @@
1# CONFIG_LOCALVERSION_AUTO is not set 1# CONFIG_LOCALVERSION_AUTO is not set
2# CONFIG_SWAP is not set 2# CONFIG_SWAP is not set
3CONFIG_SYSVIPC=y 3CONFIG_SYSVIPC=y
4CONFIG_LOG_BUF_SHIFT=13
5CONFIG_SYSFS_DEPRECATED=y 4CONFIG_SYSFS_DEPRECATED=y
6CONFIG_SYSFS_DEPRECATED_V2=y 5CONFIG_SYSFS_DEPRECATED_V2=y
7CONFIG_KALLSYMS_ALL=y 6CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_smp_defconfig b/arch/metag/configs/meta2_smp_defconfig
index 6c7b777ac276..f3306737da20 100644
--- a/arch/metag/configs/meta2_smp_defconfig
+++ b/arch/metag/configs/meta2_smp_defconfig
@@ -1,7 +1,6 @@
1# CONFIG_LOCALVERSION_AUTO is not set 1# CONFIG_LOCALVERSION_AUTO is not set
2# CONFIG_SWAP is not set 2# CONFIG_SWAP is not set
3CONFIG_SYSVIPC=y 3CONFIG_SYSVIPC=y
4CONFIG_LOG_BUF_SHIFT=13
5CONFIG_SYSFS_DEPRECATED=y 4CONFIG_SYSFS_DEPRECATED=y
6CONFIG_SYSFS_DEPRECATED_V2=y 5CONFIG_SYSFS_DEPRECATED_V2=y
7CONFIG_KALLSYMS_ALL=y 6CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/include/asm/metag_mem.h b/arch/metag/include/asm/metag_mem.h
index 3f7b54d8ccac..aa5a076df439 100644
--- a/arch/metag/include/asm/metag_mem.h
+++ b/arch/metag/include/asm/metag_mem.h
@@ -700,6 +700,9 @@
700#define SYSC_xCPARTG_AND_S 8 700#define SYSC_xCPARTG_AND_S 8
701#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */ 701#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */
702#define SYSC_xCPARTL_OR_S 16 702#define SYSC_xCPARTL_OR_S 16
703#ifdef METAC_2_1
704#define SYSC_DCPART_GCON_BIT 0x00100000 /* Coherent shared local */
705#endif /* METAC_2_1 */
703#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */ 706#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */
704#define SYSC_xCPARTG_OR_S 24 707#define SYSC_xCPARTG_OR_S 24
705#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */ 708#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */
diff --git a/arch/metag/include/uapi/asm/Kbuild b/arch/metag/include/uapi/asm/Kbuild
index 876c71f866de..84e09feb4d54 100644
--- a/arch/metag/include/uapi/asm/Kbuild
+++ b/arch/metag/include/uapi/asm/Kbuild
@@ -2,6 +2,7 @@
2include include/uapi/asm-generic/Kbuild.asm 2include include/uapi/asm-generic/Kbuild.asm
3 3
4header-y += byteorder.h 4header-y += byteorder.h
5header-y += ech.h
5header-y += ptrace.h 6header-y += ptrace.h
6header-y += resource.h 7header-y += resource.h
7header-y += sigcontext.h 8header-y += sigcontext.h
diff --git a/arch/metag/include/uapi/asm/ech.h b/arch/metag/include/uapi/asm/ech.h
new file mode 100644
index 000000000000..ac94d1cf9be4
--- /dev/null
+++ b/arch/metag/include/uapi/asm/ech.h
@@ -0,0 +1,15 @@
1#ifndef _UAPI_METAG_ECH_H
2#define _UAPI_METAG_ECH_H
3
4/*
5 * These bits can be set in the top half of the D0.8 register when DSP context
6 * switching is enabled, in order to support partial DSP context save/restore.
7 */
8
9#define TBICTX_XEXT_BIT 0x1000 /* Enable extended context save */
10#define TBICTX_XTDP_BIT 0x0800 /* DSP accumulators/RAM/templates */
11#define TBICTX_XHL2_BIT 0x0400 /* Hardware loops */
12#define TBICTX_XAXX_BIT 0x0200 /* Extended AX registers (A*.4-7) */
13#define TBICTX_XDX8_BIT 0x0100 /* Extended DX registers (D*.8-15) */
14
15#endif /* _UAPI_METAG_ECH_H */
diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index 3a589dfb966b..954548b1bea8 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -24,15 +24,21 @@
24unsigned int get_dcache_size(void) 24unsigned int get_dcache_size(void)
25{ 25{
26 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); 26 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
27 return 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS) 27 unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
28 >> METAC_CORECFG2_DCSZ_S); 28 >> METAC_CORECFG2_DCSZ_S);
29 if (config2 & METAC_CORECFG2_DCSMALL_BIT)
30 sz >>= 6;
31 return sz;
29} 32}
30 33
31unsigned int get_icache_size(void) 34unsigned int get_icache_size(void)
32{ 35{
33 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); 36 unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
34 return 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS) 37 unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
35 >> METAC_CORE_C2ICSZ_S); 38 >> METAC_CORE_C2ICSZ_S);
39 if (config2 & METAC_CORECFG2_ICSMALL_BIT)
40 sz >>= 6;
41 return sz;
36} 42}
37 43
38unsigned int get_global_dcache_size(void) 44unsigned int get_global_dcache_size(void)
@@ -61,7 +67,7 @@ static unsigned int get_thread_cache_size(unsigned int cache, int thread_id)
61 return 0; 67 return 0;
62#if PAGE_OFFSET >= LINGLOBAL_BASE 68#if PAGE_OFFSET >= LINGLOBAL_BASE
63 /* Checking for global cache */ 69 /* Checking for global cache */
64 cache_size = (cache == DCACHE ? get_global_dache_size() : 70 cache_size = (cache == DCACHE ? get_global_dcache_size() :
65 get_global_icache_size()); 71 get_global_icache_size());
66 offset = 8; 72 offset = 8;
67#else 73#else
diff --git a/arch/metag/kernel/da.c b/arch/metag/kernel/da.c
index 52aabb658fde..a35dbed6fffa 100644
--- a/arch/metag/kernel/da.c
+++ b/arch/metag/kernel/da.c
@@ -5,12 +5,14 @@
5 */ 5 */
6 6
7 7
8#include <linux/export.h>
8#include <linux/io.h> 9#include <linux/io.h>
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <asm/da.h> 11#include <asm/da.h>
11#include <asm/metag_mem.h> 12#include <asm/metag_mem.h>
12 13
13bool _metag_da_present; 14bool _metag_da_present;
15EXPORT_SYMBOL_GPL(_metag_da_present);
14 16
15int __init metag_da_probe(void) 17int __init metag_da_probe(void)
16{ 18{
diff --git a/arch/metag/kernel/head.S b/arch/metag/kernel/head.S
index 969dffabc03a..713f71d1bdfe 100644
--- a/arch/metag/kernel/head.S
+++ b/arch/metag/kernel/head.S
@@ -1,6 +1,7 @@
1 ! Copyright 2005,2006,2007,2009 Imagination Technologies 1 ! Copyright 2005,2006,2007,2009 Imagination Technologies
2 2
3#include <linux/init.h> 3#include <linux/init.h>
4#include <asm/metag_mem.h>
4#include <generated/asm-offsets.h> 5#include <generated/asm-offsets.h>
5#undef __exit 6#undef __exit
6 7
@@ -48,6 +49,13 @@ __exit:
48 .global _secondary_startup 49 .global _secondary_startup
49 .type _secondary_startup,function 50 .type _secondary_startup,function
50_secondary_startup: 51_secondary_startup:
52#if CONFIG_PAGE_OFFSET < LINGLOBAL_BASE
53 ! In case GCOn has just been turned on we need to fence any writes that
54 ! the boot thread might have performed prior to coherency taking effect.
55 MOVT D0Re0,#HI(LINSYSEVENT_WR_ATOMIC_UNLOCK)
56 MOV D1Re0,#0
57 SETD [D0Re0], D1Re0
58#endif
51 MOVT A0StP,#HI(_secondary_data_stack) 59 MOVT A0StP,#HI(_secondary_data_stack)
52 ADD A0StP,A0StP,#LO(_secondary_data_stack) 60 ADD A0StP,A0StP,#LO(_secondary_data_stack)
53 GETD A0StP,[A0StP] 61 GETD A0StP,[A0StP]
diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a876d5ff3897..366569425c52 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -22,9 +22,9 @@
22#include <linux/slab.h> 22#include <linux/slab.h>
23 23
24#include <asm/core_reg.h> 24#include <asm/core_reg.h>
25#include <asm/hwthread.h>
26#include <asm/io.h> 25#include <asm/io.h>
27#include <asm/irq.h> 26#include <asm/irq.h>
27#include <asm/processor.h>
28 28
29#include "perf_event.h" 29#include "perf_event.h"
30 30
@@ -40,10 +40,10 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
40/* PMU admin */ 40/* PMU admin */
41const char *perf_pmu_name(void) 41const char *perf_pmu_name(void)
42{ 42{
43 if (metag_pmu) 43 if (!metag_pmu)
44 return metag_pmu->pmu.name; 44 return NULL;
45 45
46 return NULL; 46 return metag_pmu->name;
47} 47}
48EXPORT_SYMBOL_GPL(perf_pmu_name); 48EXPORT_SYMBOL_GPL(perf_pmu_name);
49 49
@@ -171,6 +171,7 @@ static int metag_pmu_event_init(struct perf_event *event)
171 switch (event->attr.type) { 171 switch (event->attr.type) {
172 case PERF_TYPE_HARDWARE: 172 case PERF_TYPE_HARDWARE:
173 case PERF_TYPE_HW_CACHE: 173 case PERF_TYPE_HW_CACHE:
174 case PERF_TYPE_RAW:
174 err = _hw_perf_event_init(event); 175 err = _hw_perf_event_init(event);
175 break; 176 break;
176 177
@@ -211,9 +212,10 @@ again:
211 /* 212 /*
212 * Calculate the delta and add it to the counter. 213 * Calculate the delta and add it to the counter.
213 */ 214 */
214 delta = new_raw_count - prev_raw_count; 215 delta = (new_raw_count - prev_raw_count) & MAX_PERIOD;
215 216
216 local64_add(delta, &event->count); 217 local64_add(delta, &event->count);
218 local64_sub(delta, &hwc->period_left);
217} 219}
218 220
219int metag_pmu_event_set_period(struct perf_event *event, 221int metag_pmu_event_set_period(struct perf_event *event,
@@ -223,6 +225,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
223 s64 period = hwc->sample_period; 225 s64 period = hwc->sample_period;
224 int ret = 0; 226 int ret = 0;
225 227
228 /* The period may have been changed */
229 if (unlikely(period != hwc->last_period))
230 left += period - hwc->last_period;
231
226 if (unlikely(left <= -period)) { 232 if (unlikely(left <= -period)) {
227 left = period; 233 left = period;
228 local64_set(&hwc->period_left, left); 234 local64_set(&hwc->period_left, left);
@@ -240,8 +246,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
240 if (left > (s64)metag_pmu->max_period) 246 if (left > (s64)metag_pmu->max_period)
241 left = metag_pmu->max_period; 247 left = metag_pmu->max_period;
242 248
243 if (metag_pmu->write) 249 if (metag_pmu->write) {
244 metag_pmu->write(idx, (u64)(-left) & MAX_PERIOD); 250 local64_set(&hwc->prev_count, -(s32)left);
251 metag_pmu->write(idx, -left & MAX_PERIOD);
252 }
245 253
246 perf_event_update_userpage(event); 254 perf_event_update_userpage(event);
247 255
@@ -549,6 +557,10 @@ static int _hw_perf_event_init(struct perf_event *event)
549 if (err) 557 if (err)
550 return err; 558 return err;
551 break; 559 break;
560
561 case PERF_TYPE_RAW:
562 mapping = attr->config;
563 break;
552 } 564 }
553 565
554 /* Return early if the event is unsupported */ 566 /* Return early if the event is unsupported */
@@ -610,15 +622,13 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
610 WARN_ONCE((config != 0x100), 622 WARN_ONCE((config != 0x100),
611 "invalid configuration (%d) for counter (%d)\n", 623 "invalid configuration (%d) for counter (%d)\n",
612 config, idx); 624 config, idx);
613 625 local64_set(&event->prev_count, __core_reg_get(TXTACTCYC));
614 /* Reset the cycle count */
615 __core_reg_set(TXTACTCYC, 0);
616 goto unlock; 626 goto unlock;
617 } 627 }
618 628
619 /* Check for a core internal or performance channel event. */ 629 /* Check for a core internal or performance channel event. */
620 if (tmp) { 630 if (tmp) {
621 void *perf_addr = (void *)PERF_COUNT(idx); 631 void *perf_addr;
622 632
623 /* 633 /*
624 * Anything other than a cycle count will write the low- 634 * 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)
632 case 0xf0: 642 case 0xf0:
633 perf_addr = (void *)PERF_CHAN(idx); 643 perf_addr = (void *)PERF_CHAN(idx);
634 break; 644 break;
645
646 default:
647 perf_addr = NULL;
648 break;
635 } 649 }
636 650
637 metag_out32((tmp & 0x0f), perf_addr); 651 if (perf_addr)
652 metag_out32((config & 0x0f), perf_addr);
638 653
639 /* 654 /*
640 * Now we use the high nibble as the performance event to 655 * 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)
643 config = tmp >> 4; 658 config = tmp >> 4;
644 } 659 }
645 660
646 /*
647 * Enabled counters start from 0. Early cores clear the count on
648 * write but newer cores don't, so we make sure that the count is
649 * set to 0.
650 */
651 tmp = ((config & 0xf) << 28) | 661 tmp = ((config & 0xf) << 28) |
652 ((1 << 24) << cpu_2_hwthread_id[get_cpu()]); 662 ((1 << 24) << hard_processor_id());
663 if (metag_pmu->max_period)
664 /*
665 * Cores supporting overflow interrupts may have had the counter
666 * set to a specific value that needs preserving.
667 */
668 tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff;
669 else
670 /*
671 * Older cores reset the counter on write, so prev_count needs
672 * resetting too so we can calculate a correct delta.
673 */
674 local64_set(&event->prev_count, 0);
675
653 metag_out32(tmp, PERF_COUNT(idx)); 676 metag_out32(tmp, PERF_COUNT(idx));
654unlock: 677unlock:
655 raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 678 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
@@ -693,9 +716,8 @@ static u64 metag_pmu_read_counter(int idx)
693{ 716{
694 u32 tmp = 0; 717 u32 tmp = 0;
695 718
696 /* The act of reading the cycle counter also clears it */
697 if (METAG_INST_COUNTER == idx) { 719 if (METAG_INST_COUNTER == idx) {
698 __core_reg_swap(TXTACTCYC, tmp); 720 tmp = __core_reg_get(TXTACTCYC);
699 goto out; 721 goto out;
700 } 722 }
701 723
@@ -764,10 +786,16 @@ static irqreturn_t metag_pmu_counter_overflow(int irq, void *dev)
764 786
765 /* 787 /*
766 * Enable the counter again once core overflow processing has 788 * Enable the counter again once core overflow processing has
767 * completed. 789 * completed. Note the counter value may have been modified while it was
790 * inactive to set it up ready for the next interrupt.
768 */ 791 */
769 if (!perf_event_overflow(event, &sampledata, regs)) 792 if (!perf_event_overflow(event, &sampledata, regs)) {
793 __global_lock2(flags);
794 counter = (counter & 0xff000000) |
795 (metag_in32(PERF_COUNT(idx)) & 0x00ffffff);
770 metag_out32(counter, PERF_COUNT(idx)); 796 metag_out32(counter, PERF_COUNT(idx));
797 __global_unlock2(flags);
798 }
771 799
772 return IRQ_HANDLED; 800 return IRQ_HANDLED;
773} 801}
@@ -830,7 +858,7 @@ static int __init init_hw_perf_events(void)
830 metag_pmu->max_period = 0; 858 metag_pmu->max_period = 0;
831 } 859 }
832 860
833 metag_pmu->name = "Meta 2"; 861 metag_pmu->name = "meta2";
834 metag_pmu->version = version; 862 metag_pmu->version = version;
835 metag_pmu->pmu = pmu; 863 metag_pmu->pmu = pmu;
836 } 864 }
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 47a8828615a5..7563628822bd 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,
288 return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf); 288 return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf);
289} 289}
290 290
291static int metag_tls_get(struct task_struct *target,
292 const struct user_regset *regset,
293 unsigned int pos, unsigned int count,
294 void *kbuf, void __user *ubuf)
295{
296 void __user *tls = target->thread.tls_ptr;
297 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
298}
299
300static int metag_tls_set(struct task_struct *target,
301 const struct user_regset *regset,
302 unsigned int pos, unsigned int count,
303 const void *kbuf, const void __user *ubuf)
304{
305 int ret;
306 void __user *tls;
307
308 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
309 if (ret)
310 return ret;
311
312 target->thread.tls_ptr = tls;
313 return ret;
314}
315
291enum metag_regset { 316enum metag_regset {
292 REGSET_GENERAL, 317 REGSET_GENERAL,
293 REGSET_CBUF, 318 REGSET_CBUF,
294 REGSET_READPIPE, 319 REGSET_READPIPE,
320 REGSET_TLS,
295}; 321};
296 322
297static const struct user_regset metag_regsets[] = { 323static const struct user_regset metag_regsets[] = {
@@ -319,6 +345,14 @@ static const struct user_regset metag_regsets[] = {
319 .get = metag_rp_state_get, 345 .get = metag_rp_state_get,
320 .set = metag_rp_state_set, 346 .set = metag_rp_state_set,
321 }, 347 },
348 [REGSET_TLS] = {
349 .core_note_type = NT_METAG_TLS,
350 .n = 1,
351 .size = sizeof(void *),
352 .align = sizeof(void *),
353 .get = metag_tls_get,
354 .set = metag_tls_set,
355 },
322}; 356};
323 357
324static const struct user_regset_view user_metag_view = { 358static const struct user_regset_view user_metag_view = {
diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c
index 879246170aec..4f5726f1a55b 100644
--- a/arch/metag/kernel/setup.c
+++ b/arch/metag/kernel/setup.c
@@ -124,6 +124,7 @@ struct machine_desc *machine_desc __initdata;
124u8 cpu_2_hwthread_id[NR_CPUS] __read_mostly = { 124u8 cpu_2_hwthread_id[NR_CPUS] __read_mostly = {
125 [0 ... NR_CPUS-1] = BAD_HWTHREAD_ID 125 [0 ... NR_CPUS-1] = BAD_HWTHREAD_ID
126}; 126};
127EXPORT_SYMBOL_GPL(cpu_2_hwthread_id);
127 128
128/* 129/*
129 * Map a hardware thread ID to a Linux CPU number 130 * Map a hardware thread ID to a Linux CPU number
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index 4de8fc8e31a5..f443ec9a7cbe 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -28,6 +28,8 @@
28#include <asm/cachepart.h> 28#include <asm/cachepart.h>
29#include <asm/core_reg.h> 29#include <asm/core_reg.h>
30#include <asm/cpu.h> 30#include <asm/cpu.h>
31#include <asm/global_lock.h>
32#include <asm/metag_mem.h>
31#include <asm/mmu_context.h> 33#include <asm/mmu_context.h>
32#include <asm/pgtable.h> 34#include <asm/pgtable.h>
33#include <asm/pgalloc.h> 35#include <asm/pgalloc.h>
@@ -37,6 +39,9 @@
37#include <asm/hwthread.h> 39#include <asm/hwthread.h>
38#include <asm/traps.h> 40#include <asm/traps.h>
39 41
42#define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
43#define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
44
40DECLARE_PER_CPU(PTBI, pTBI); 45DECLARE_PER_CPU(PTBI, pTBI);
41 46
42void *secondary_data_stack; 47void *secondary_data_stack;
@@ -99,6 +104,114 @@ int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
99 return 0; 104 return 0;
100} 105}
101 106
107/**
108 * describe_cachepart_change: describe a change to cache partitions.
109 * @thread: Hardware thread number.
110 * @label: Label of cache type, e.g. "dcache" or "icache".
111 * @sz: Total size of the cache.
112 * @old: Old cache partition configuration (*CPART* register).
113 * @new: New cache partition configuration (*CPART* register).
114 *
115 * If the cache partition has changed, prints a message to the log describing
116 * those changes.
117 */
118static __cpuinit void describe_cachepart_change(unsigned int thread,
119 const char *label,
120 unsigned int sz,
121 unsigned int old,
122 unsigned int new)
123{
124 unsigned int lor1, land1, gor1, gand1;
125 unsigned int lor2, land2, gor2, gand2;
126 unsigned int diff = old ^ new;
127
128 if (!diff)
129 return;
130
131 pr_info("Thread %d: %s partition changed:", thread, label);
132 if (diff & (SYSC_xCPARTL_OR_BITS | SYSC_xCPARTL_AND_BITS)) {
133 lor1 = (old & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
134 lor2 = (new & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
135 land1 = (old & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
136 land2 = (new & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
137 pr_cont(" L:%#x+%#x->%#x+%#x",
138 (lor1 * sz) >> 4,
139 ((land1 + 1) * sz) >> 4,
140 (lor2 * sz) >> 4,
141 ((land2 + 1) * sz) >> 4);
142 }
143 if (diff & (SYSC_xCPARTG_OR_BITS | SYSC_xCPARTG_AND_BITS)) {
144 gor1 = (old & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
145 gor2 = (new & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
146 gand1 = (old & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
147 gand2 = (new & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
148 pr_cont(" G:%#x+%#x->%#x+%#x",
149 (gor1 * sz) >> 4,
150 ((gand1 + 1) * sz) >> 4,
151 (gor2 * sz) >> 4,
152 ((gand2 + 1) * sz) >> 4);
153 }
154 if (diff & SYSC_CWRMODE_BIT)
155 pr_cont(" %sWR",
156 (new & SYSC_CWRMODE_BIT) ? "+" : "-");
157 if (diff & SYSC_DCPART_GCON_BIT)
158 pr_cont(" %sGCOn",
159 (new & SYSC_DCPART_GCON_BIT) ? "+" : "-");
160 pr_cont("\n");
161}
162
163/**
164 * setup_smp_cache: ensure cache coherency for new SMP thread.
165 * @thread: New hardware thread number.
166 *
167 * Ensures that coherency is enabled and that the threads share the same cache
168 * partitions.
169 */
170static __cpuinit void setup_smp_cache(unsigned int thread)
171{
172 unsigned int this_thread, lflags;
173 unsigned int dcsz, dcpart_this, dcpart_old, dcpart_new;
174 unsigned int icsz, icpart_old, icpart_new;
175
176 /*
177 * Copy over the current thread's cache partition configuration to the
178 * new thread so that they share cache partitions.
179 */
180 __global_lock2(lflags);
181 this_thread = hard_processor_id();
182 /* Share dcache partition */
183 dcpart_this = metag_in32(SYSC_DCPART(this_thread));
184 dcpart_old = metag_in32(SYSC_DCPART(thread));
185 dcpart_new = dcpart_this;
186#if PAGE_OFFSET < LINGLOBAL_BASE
187 /*
188 * For the local data cache to be coherent the threads must also have
189 * GCOn enabled.
190 */
191 dcpart_new |= SYSC_DCPART_GCON_BIT;
192 metag_out32(dcpart_new, SYSC_DCPART(this_thread));
193#endif
194 metag_out32(dcpart_new, SYSC_DCPART(thread));
195 /* Share icache partition too */
196 icpart_new = metag_in32(SYSC_ICPART(this_thread));
197 icpart_old = metag_in32(SYSC_ICPART(thread));
198 metag_out32(icpart_new, SYSC_ICPART(thread));
199 __global_unlock2(lflags);
200
201 /*
202 * Log if the cache partitions were altered so the user is aware of any
203 * potential unintentional cache wastage.
204 */
205 dcsz = get_dcache_size();
206 icsz = get_dcache_size();
207 describe_cachepart_change(this_thread, "dcache", dcsz,
208 dcpart_this, dcpart_new);
209 describe_cachepart_change(thread, "dcache", dcsz,
210 dcpart_old, dcpart_new);
211 describe_cachepart_change(thread, "icache", icsz,
212 icpart_old, icpart_new);
213}
214
102int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) 215int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
103{ 216{
104 unsigned int thread = cpu_2_hwthread_id[cpu]; 217 unsigned int thread = cpu_2_hwthread_id[cpu];
@@ -108,6 +221,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
108 221
109 flush_tlb_all(); 222 flush_tlb_all();
110 223
224 setup_smp_cache(thread);
225
111 /* 226 /*
112 * Tell the secondary CPU where to find its idle thread's stack. 227 * Tell the secondary CPU where to find its idle thread's stack.
113 */ 228 */
diff --git a/arch/metag/mm/Kconfig b/arch/metag/mm/Kconfig
index 975f2f4e3ecf..794f26a187f9 100644
--- a/arch/metag/mm/Kconfig
+++ b/arch/metag/mm/Kconfig
@@ -98,9 +98,6 @@ config MAX_ACTIVE_REGIONS
98 default "2" if SPARSEMEM 98 default "2" if SPARSEMEM
99 default "1" 99 default "1"
100 100
101config ARCH_POPULATES_NODE_MAP
102 def_bool y
103
104config ARCH_SELECT_MEMORY_MODEL 101config ARCH_SELECT_MEMORY_MODEL
105 def_bool y 102 def_bool y
106 103
diff --git a/arch/metag/oprofile/Makefile b/arch/metag/oprofile/Makefile
new file mode 100644
index 000000000000..c9639d4734d6
--- /dev/null
+++ b/arch/metag/oprofile/Makefile
@@ -0,0 +1,17 @@
1obj-$(CONFIG_OPROFILE) += oprofile.o
2
3oprofile-core-y += buffer_sync.o
4oprofile-core-y += cpu_buffer.o
5oprofile-core-y += event_buffer.o
6oprofile-core-y += oprof.o
7oprofile-core-y += oprofile_files.o
8oprofile-core-y += oprofile_stats.o
9oprofile-core-y += oprofilefs.o
10oprofile-core-y += timer_int.o
11oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o
12
13oprofile-y += backtrace.o
14oprofile-y += common.o
15oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y))
16
17ccflags-y += -Werror
diff --git a/arch/metag/oprofile/backtrace.c b/arch/metag/oprofile/backtrace.c
new file mode 100644
index 000000000000..7cc3f37cb40e
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.c
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2010-2013 Imagination Technologies Ltd.
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 */
8
9#include <linux/oprofile.h>
10#include <linux/uaccess.h>
11#include <asm/processor.h>
12#include <asm/stacktrace.h>
13
14#include "backtrace.h"
15
16static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth)
17{
18 while (depth-- && access_ok(VERIFY_READ, fp, 8)) {
19 unsigned long addr;
20 unsigned long __user *fpnew;
21 if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr)))
22 break;
23 addr -= 4;
24
25 oprofile_add_trace(addr);
26
27 /* stack grows up, so frame pointers must decrease */
28 if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew)))
29 break;
30 if (fpnew >= fp)
31 break;
32 fp = fpnew;
33 }
34}
35
36static int kernel_backtrace_frame(struct stackframe *frame, void *data)
37{
38 unsigned int *depth = data;
39
40 oprofile_add_trace(frame->pc);
41
42 /* decrement depth and stop if we reach 0 */
43 if ((*depth)-- == 0)
44 return 1;
45
46 /* otherwise onto the next frame */
47 return 0;
48}
49
50void metag_backtrace(struct pt_regs * const regs, unsigned int depth)
51{
52 if (user_mode(regs)) {
53 unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0;
54 user_backtrace_fp((unsigned long __user __force *)fp, depth);
55 } else {
56 struct stackframe frame;
57 frame.fp = regs->ctx.AX[1].U0; /* A0FrP */
58 frame.sp = user_stack_pointer(regs); /* A0StP */
59 frame.lr = 0; /* from stack */
60 frame.pc = regs->ctx.CurrPC; /* PC */
61 walk_stackframe(&frame, &kernel_backtrace_frame, &depth);
62 }
63}
diff --git a/arch/metag/oprofile/backtrace.h b/arch/metag/oprofile/backtrace.h
new file mode 100644
index 000000000000..c0fcc4265abb
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.h
@@ -0,0 +1,6 @@
1#ifndef _METAG_OPROFILE_BACKTRACE_H
2#define _METAG_OPROFILE_BACKTRACE_H
3
4void metag_backtrace(struct pt_regs * const regs, unsigned int depth);
5
6#endif
diff --git a/arch/metag/oprofile/common.c b/arch/metag/oprofile/common.c
new file mode 100644
index 000000000000..ba26152b3c00
--- /dev/null
+++ b/arch/metag/oprofile/common.c
@@ -0,0 +1,66 @@
1/*
2 * arch/metag/oprofile/common.c
3 *
4 * Copyright (C) 2013 Imagination Technologies Ltd.
5 *
6 * Based on arch/sh/oprofile/common.c:
7 *
8 * Copyright (C) 2003 - 2010 Paul Mundt
9 *
10 * Based on arch/mips/oprofile/common.c:
11 *
12 * Copyright (C) 2004, 2005 Ralf Baechle
13 * Copyright (C) 2005 MIPS Technologies, Inc.
14 *
15 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file "COPYING" in the main directory of this archive
17 * for more details.
18 */
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/oprofile.h>
22#include <linux/perf_event.h>
23#include <linux/slab.h>
24
25#include "backtrace.h"
26
27#ifdef CONFIG_HW_PERF_EVENTS
28/*
29 * This will need to be reworked when multiple PMUs are supported.
30 */
31static char *metag_pmu_op_name;
32
33char *op_name_from_perf_id(void)
34{
35 return metag_pmu_op_name;
36}
37
38int __init oprofile_arch_init(struct oprofile_operations *ops)
39{
40 ops->backtrace = metag_backtrace;
41
42 if (perf_num_counters() == 0)
43 return -ENODEV;
44
45 metag_pmu_op_name = kasprintf(GFP_KERNEL, "metag/%s",
46 perf_pmu_name());
47 if (unlikely(!metag_pmu_op_name))
48 return -ENOMEM;
49
50 return oprofile_perf_init(ops);
51}
52
53void oprofile_arch_exit(void)
54{
55 oprofile_perf_exit();
56 kfree(metag_pmu_op_name);
57}
58#else
59int __init oprofile_arch_init(struct oprofile_operations *ops)
60{
61 ops->backtrace = metag_backtrace;
62 /* fall back to timer interrupt PC sampling */
63 return -ENODEV;
64}
65void oprofile_arch_exit(void) {}
66#endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index a827057c7927..54237af0b07c 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -39,9 +39,6 @@ config RWSEM_GENERIC_SPINLOCK
39config ZONE_DMA 39config ZONE_DMA
40 def_bool y 40 def_bool y
41 41
42config ARCH_POPULATES_NODE_MAP
43 def_bool y
44
45config RWSEM_XCHGADD_ALGORITHM 42config RWSEM_XCHGADD_ALGORITHM
46 bool 43 bool
47 44