Commit 87c1f0f8c9442c86cbb343b9324bef8312029d7d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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
Showing 23 changed files Side-by-side Diff
- arch/metag/Kconfig
- arch/metag/Makefile
- arch/metag/boot/dts/Makefile
- arch/metag/configs/meta1_defconfig
- arch/metag/configs/meta2_defconfig
- arch/metag/configs/meta2_smp_defconfig
- arch/metag/include/asm/metag_mem.h
- arch/metag/include/uapi/asm/Kbuild
- arch/metag/include/uapi/asm/ech.h
- arch/metag/kernel/cachepart.c
- arch/metag/kernel/da.c
- arch/metag/kernel/head.S
- arch/metag/kernel/perf/perf_event.c
- arch/metag/kernel/ptrace.c
- arch/metag/kernel/setup.c
- arch/metag/kernel/smp.c
- arch/metag/mm/Kconfig
- arch/metag/oprofile/Makefile
- arch/metag/oprofile/backtrace.c
- arch/metag/oprofile/backtrace.h
- arch/metag/oprofile/common.c
- arch/microblaze/Kconfig
- include/uapi/linux/elf.h
arch/metag/Kconfig
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | select HAVE_MEMBLOCK |
26 | 26 | select HAVE_MEMBLOCK_NODE_MAP |
27 | 27 | select HAVE_MOD_ARCH_SPECIFIC |
28 | + select HAVE_OPROFILE | |
28 | 29 | select HAVE_PERF_EVENTS |
29 | 30 | select HAVE_SYSCALL_TRACEPOINTS |
30 | 31 | select IRQ_DOMAIN |
... | ... | @@ -208,6 +209,9 @@ |
208 | 209 | |
209 | 210 | When disabled, Performance Counters information will be collected |
210 | 211 | based on Timer Interrupt. |
212 | + | |
213 | +config HW_PERF_EVENTS | |
214 | + def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS | |
211 | 215 | |
212 | 216 | config METAG_DA |
213 | 217 | bool "DA support" |
arch/metag/Makefile
arch/metag/boot/dts/Makefile
... | ... | @@ -4,14 +4,18 @@ |
4 | 4 | builtindtb-y := skeleton |
5 | 5 | |
6 | 6 | ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"") |
7 | - builtindtb-y := $(CONFIG_METAG_BUILTIN_DTB_NAME) | |
7 | + builtindtb-y := $(patsubst "%",%,$(CONFIG_METAG_BUILTIN_DTB_NAME)) | |
8 | 8 | endif |
9 | -obj-$(CONFIG_METAG_BUILTIN_DTB) += $(patsubst "%",%,$(builtindtb-y)).dtb.o | |
10 | 9 | |
10 | +dtb-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb | |
11 | +obj-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb.o | |
12 | + | |
11 | 13 | targets += dtbs |
12 | 14 | targets += $(dtb-y) |
13 | 15 | |
16 | +.SECONDARY: $(obj)/$(builtindtb-y).dtb.S | |
17 | + | |
14 | 18 | dtbs: $(addprefix $(obj)/, $(dtb-y)) |
15 | 19 | |
16 | -clean-files += *.dtb | |
20 | +clean-files += *.dtb *.dtb.S |
arch/metag/configs/meta1_defconfig
arch/metag/configs/meta2_defconfig
arch/metag/configs/meta2_smp_defconfig
arch/metag/include/asm/metag_mem.h
... | ... | @@ -700,6 +700,9 @@ |
700 | 700 | #define SYSC_xCPARTG_AND_S 8 |
701 | 701 | #define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */ |
702 | 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 | 706 | #define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */ |
704 | 707 | #define SYSC_xCPARTG_OR_S 24 |
705 | 708 | #define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */ |
arch/metag/include/uapi/asm/Kbuild
arch/metag/include/uapi/asm/ech.h
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 */ |
arch/metag/kernel/cachepart.c
... | ... | @@ -24,15 +24,21 @@ |
24 | 24 | unsigned int get_dcache_size(void) |
25 | 25 | { |
26 | 26 | unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); |
27 | - return 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS) | |
28 | - >> METAC_CORECFG2_DCSZ_S); | |
27 | + unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS) | |
28 | + >> METAC_CORECFG2_DCSZ_S); | |
29 | + if (config2 & METAC_CORECFG2_DCSMALL_BIT) | |
30 | + sz >>= 6; | |
31 | + return sz; | |
29 | 32 | } |
30 | 33 | |
31 | 34 | unsigned int get_icache_size(void) |
32 | 35 | { |
33 | 36 | unsigned int config2 = metag_in32(METAC_CORE_CONFIG2); |
34 | - return 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS) | |
35 | - >> METAC_CORE_C2ICSZ_S); | |
37 | + unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS) | |
38 | + >> METAC_CORE_C2ICSZ_S); | |
39 | + if (config2 & METAC_CORECFG2_ICSMALL_BIT) | |
40 | + sz >>= 6; | |
41 | + return sz; | |
36 | 42 | } |
37 | 43 | |
38 | 44 | unsigned int get_global_dcache_size(void) |
... | ... | @@ -61,7 +67,7 @@ |
61 | 67 | return 0; |
62 | 68 | #if PAGE_OFFSET >= LINGLOBAL_BASE |
63 | 69 | /* Checking for global cache */ |
64 | - cache_size = (cache == DCACHE ? get_global_dache_size() : | |
70 | + cache_size = (cache == DCACHE ? get_global_dcache_size() : | |
65 | 71 | get_global_icache_size()); |
66 | 72 | offset = 8; |
67 | 73 | #else |
arch/metag/kernel/da.c
... | ... | @@ -5,12 +5,14 @@ |
5 | 5 | */ |
6 | 6 | |
7 | 7 | |
8 | +#include <linux/export.h> | |
8 | 9 | #include <linux/io.h> |
9 | 10 | #include <linux/kernel.h> |
10 | 11 | #include <asm/da.h> |
11 | 12 | #include <asm/metag_mem.h> |
12 | 13 | |
13 | 14 | bool _metag_da_present; |
15 | +EXPORT_SYMBOL_GPL(_metag_da_present); | |
14 | 16 | |
15 | 17 | int __init metag_da_probe(void) |
16 | 18 | { |
arch/metag/kernel/head.S
1 | 1 | ! Copyright 2005,2006,2007,2009 Imagination Technologies |
2 | 2 | |
3 | 3 | #include <linux/init.h> |
4 | +#include <asm/metag_mem.h> | |
4 | 5 | #include <generated/asm-offsets.h> |
5 | 6 | #undef __exit |
6 | 7 | |
... | ... | @@ -48,6 +49,13 @@ |
48 | 49 | .global _secondary_startup |
49 | 50 | .type _secondary_startup,function |
50 | 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 | 59 | MOVT A0StP,#HI(_secondary_data_stack) |
52 | 60 | ADD A0StP,A0StP,#LO(_secondary_data_stack) |
53 | 61 | GETD A0StP,[A0StP] |
arch/metag/kernel/perf/perf_event.c
... | ... | @@ -22,9 +22,9 @@ |
22 | 22 | #include <linux/slab.h> |
23 | 23 | |
24 | 24 | #include <asm/core_reg.h> |
25 | -#include <asm/hwthread.h> | |
26 | 25 | #include <asm/io.h> |
27 | 26 | #include <asm/irq.h> |
27 | +#include <asm/processor.h> | |
28 | 28 | |
29 | 29 | #include "perf_event.h" |
30 | 30 | |
31 | 31 | |
... | ... | @@ -40,10 +40,10 @@ |
40 | 40 | /* PMU admin */ |
41 | 41 | const char *perf_pmu_name(void) |
42 | 42 | { |
43 | - if (metag_pmu) | |
44 | - return metag_pmu->pmu.name; | |
43 | + if (!metag_pmu) | |
44 | + return NULL; | |
45 | 45 | |
46 | - return NULL; | |
46 | + return metag_pmu->name; | |
47 | 47 | } |
48 | 48 | EXPORT_SYMBOL_GPL(perf_pmu_name); |
49 | 49 | |
... | ... | @@ -171,6 +171,7 @@ |
171 | 171 | switch (event->attr.type) { |
172 | 172 | case PERF_TYPE_HARDWARE: |
173 | 173 | case PERF_TYPE_HW_CACHE: |
174 | + case PERF_TYPE_RAW: | |
174 | 175 | err = _hw_perf_event_init(event); |
175 | 176 | break; |
176 | 177 | |
177 | 178 | |
... | ... | @@ -211,9 +212,10 @@ |
211 | 212 | /* |
212 | 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 | 217 | local64_add(delta, &event->count); |
218 | + local64_sub(delta, &hwc->period_left); | |
217 | 219 | } |
218 | 220 | |
219 | 221 | int metag_pmu_event_set_period(struct perf_event *event, |
... | ... | @@ -223,6 +225,10 @@ |
223 | 225 | s64 period = hwc->sample_period; |
224 | 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 | 232 | if (unlikely(left <= -period)) { |
227 | 233 | left = period; |
228 | 234 | local64_set(&hwc->period_left, left); |
... | ... | @@ -240,8 +246,10 @@ |
240 | 246 | if (left > (s64)metag_pmu->max_period) |
241 | 247 | left = metag_pmu->max_period; |
242 | 248 | |
243 | - if (metag_pmu->write) | |
244 | - metag_pmu->write(idx, (u64)(-left) & MAX_PERIOD); | |
249 | + if (metag_pmu->write) { | |
250 | + local64_set(&hwc->prev_count, -(s32)left); | |
251 | + metag_pmu->write(idx, -left & MAX_PERIOD); | |
252 | + } | |
245 | 253 | |
246 | 254 | perf_event_update_userpage(event); |
247 | 255 | |
... | ... | @@ -549,6 +557,10 @@ |
549 | 557 | if (err) |
550 | 558 | return err; |
551 | 559 | break; |
560 | + | |
561 | + case PERF_TYPE_RAW: | |
562 | + mapping = attr->config; | |
563 | + break; | |
552 | 564 | } |
553 | 565 | |
554 | 566 | /* Return early if the event is unsupported */ |
555 | 567 | |
... | ... | @@ -610,15 +622,13 @@ |
610 | 622 | WARN_ONCE((config != 0x100), |
611 | 623 | "invalid configuration (%d) for counter (%d)\n", |
612 | 624 | config, idx); |
613 | - | |
614 | - /* Reset the cycle count */ | |
615 | - __core_reg_set(TXTACTCYC, 0); | |
625 | + local64_set(&event->prev_count, __core_reg_get(TXTACTCYC)); | |
616 | 626 | goto unlock; |
617 | 627 | } |
618 | 628 | |
619 | 629 | /* Check for a core internal or performance channel event. */ |
620 | 630 | if (tmp) { |
621 | - void *perf_addr = (void *)PERF_COUNT(idx); | |
631 | + void *perf_addr; | |
622 | 632 | |
623 | 633 | /* |
624 | 634 | * Anything other than a cycle count will write the low- |
625 | 635 | |
... | ... | @@ -632,9 +642,14 @@ |
632 | 642 | case 0xf0: |
633 | 643 | perf_addr = (void *)PERF_CHAN(idx); |
634 | 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 | 655 | * Now we use the high nibble as the performance event to |
641 | 656 | |
... | ... | @@ -643,13 +658,21 @@ |
643 | 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 | 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 | 676 | metag_out32(tmp, PERF_COUNT(idx)); |
654 | 677 | unlock: |
655 | 678 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); |
656 | 679 | |
... | ... | @@ -693,9 +716,8 @@ |
693 | 716 | { |
694 | 717 | u32 tmp = 0; |
695 | 718 | |
696 | - /* The act of reading the cycle counter also clears it */ | |
697 | 719 | if (METAG_INST_COUNTER == idx) { |
698 | - __core_reg_swap(TXTACTCYC, tmp); | |
720 | + tmp = __core_reg_get(TXTACTCYC); | |
699 | 721 | goto out; |
700 | 722 | } |
701 | 723 | |
702 | 724 | |
703 | 725 | |
... | ... | @@ -764,10 +786,16 @@ |
764 | 786 | |
765 | 787 | /* |
766 | 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 | 796 | metag_out32(counter, PERF_COUNT(idx)); |
797 | + __global_unlock2(flags); | |
798 | + } | |
771 | 799 | |
772 | 800 | return IRQ_HANDLED; |
773 | 801 | } |
... | ... | @@ -830,7 +858,7 @@ |
830 | 858 | metag_pmu->max_period = 0; |
831 | 859 | } |
832 | 860 | |
833 | - metag_pmu->name = "Meta 2"; | |
861 | + metag_pmu->name = "meta2"; | |
834 | 862 | metag_pmu->version = version; |
835 | 863 | metag_pmu->pmu = pmu; |
836 | 864 | } |
arch/metag/kernel/ptrace.c
... | ... | @@ -288,10 +288,36 @@ |
288 | 288 | return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf); |
289 | 289 | } |
290 | 290 | |
291 | +static 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 | + | |
300 | +static 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 | + | |
291 | 316 | enum metag_regset { |
292 | 317 | REGSET_GENERAL, |
293 | 318 | REGSET_CBUF, |
294 | 319 | REGSET_READPIPE, |
320 | + REGSET_TLS, | |
295 | 321 | }; |
296 | 322 | |
297 | 323 | static const struct user_regset metag_regsets[] = { |
... | ... | @@ -318,6 +344,14 @@ |
318 | 344 | .align = sizeof(long long), |
319 | 345 | .get = metag_rp_state_get, |
320 | 346 | .set = metag_rp_state_set, |
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, | |
321 | 355 | }, |
322 | 356 | }; |
323 | 357 |
arch/metag/kernel/setup.c
arch/metag/kernel/smp.c
... | ... | @@ -28,6 +28,8 @@ |
28 | 28 | #include <asm/cachepart.h> |
29 | 29 | #include <asm/core_reg.h> |
30 | 30 | #include <asm/cpu.h> |
31 | +#include <asm/global_lock.h> | |
32 | +#include <asm/metag_mem.h> | |
31 | 33 | #include <asm/mmu_context.h> |
32 | 34 | #include <asm/pgtable.h> |
33 | 35 | #include <asm/pgalloc.h> |
... | ... | @@ -37,6 +39,9 @@ |
37 | 39 | #include <asm/hwthread.h> |
38 | 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 | + | |
40 | 45 | DECLARE_PER_CPU(PTBI, pTBI); |
41 | 46 | |
42 | 47 | void *secondary_data_stack; |
... | ... | @@ -99,6 +104,114 @@ |
99 | 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 | + */ | |
118 | +static __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 | + */ | |
170 | +static __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 | + | |
102 | 215 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) |
103 | 216 | { |
104 | 217 | unsigned int thread = cpu_2_hwthread_id[cpu]; |
... | ... | @@ -107,6 +220,8 @@ |
107 | 220 | load_pgd(swapper_pg_dir, thread); |
108 | 221 | |
109 | 222 | flush_tlb_all(); |
223 | + | |
224 | + setup_smp_cache(thread); | |
110 | 225 | |
111 | 226 | /* |
112 | 227 | * Tell the secondary CPU where to find its idle thread's stack. |
arch/metag/mm/Kconfig
arch/metag/oprofile/Makefile
1 | +obj-$(CONFIG_OPROFILE) += oprofile.o | |
2 | + | |
3 | +oprofile-core-y += buffer_sync.o | |
4 | +oprofile-core-y += cpu_buffer.o | |
5 | +oprofile-core-y += event_buffer.o | |
6 | +oprofile-core-y += oprof.o | |
7 | +oprofile-core-y += oprofile_files.o | |
8 | +oprofile-core-y += oprofile_stats.o | |
9 | +oprofile-core-y += oprofilefs.o | |
10 | +oprofile-core-y += timer_int.o | |
11 | +oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o | |
12 | + | |
13 | +oprofile-y += backtrace.o | |
14 | +oprofile-y += common.o | |
15 | +oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y)) | |
16 | + | |
17 | +ccflags-y += -Werror |
arch/metag/oprofile/backtrace.c
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 | + | |
16 | +static 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 | + | |
36 | +static 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 | + | |
50 | +void 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 | +} |
arch/metag/oprofile/backtrace.h
arch/metag/oprofile/common.c
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 | + */ | |
31 | +static char *metag_pmu_op_name; | |
32 | + | |
33 | +char *op_name_from_perf_id(void) | |
34 | +{ | |
35 | + return metag_pmu_op_name; | |
36 | +} | |
37 | + | |
38 | +int __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 | + | |
53 | +void oprofile_arch_exit(void) | |
54 | +{ | |
55 | + oprofile_perf_exit(); | |
56 | + kfree(metag_pmu_op_name); | |
57 | +} | |
58 | +#else | |
59 | +int __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 | +} | |
65 | +void oprofile_arch_exit(void) {} | |
66 | +#endif /* CONFIG_HW_PERF_EVENTS */ |
arch/microblaze/Kconfig
include/uapi/linux/elf.h
... | ... | @@ -397,6 +397,7 @@ |
397 | 397 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ |
398 | 398 | #define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */ |
399 | 399 | #define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */ |
400 | +#define NT_METAG_TLS 0x502 /* Metag TLS pointer */ | |
400 | 401 | |
401 | 402 | |
402 | 403 | /* Note header in a PT_NOTE section */ |