aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/cputable.c74
-rw-r--r--arch/powerpc/kernel/head_32.S12
-rw-r--r--arch/powerpc/kernel/pmc.c5
-rw-r--r--arch/powerpc/kernel/traps.c2
-rw-r--r--arch/powerpc/oprofile/Makefile1
-rw-r--r--arch/powerpc/oprofile/common.c61
-rw-r--r--arch/powerpc/oprofile/op_model_7450.c206
7 files changed, 293 insertions, 68 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 1d85cedbbb7b..f7f2a830fca1 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -545,7 +545,11 @@ struct cpu_spec cpu_specs[] = {
545 .icache_bsize = 32, 545 .icache_bsize = 32,
546 .dcache_bsize = 32, 546 .dcache_bsize = 32,
547 .num_pmcs = 6, 547 .num_pmcs = 6,
548 .cpu_setup = __setup_cpu_745x 548 .cpu_setup = __setup_cpu_745x,
549#ifdef CONFIG_OPROFILE
550 .oprofile_cpu_type = "ppc/7450",
551 .oprofile_model = &op_model_7450,
552#endif
549 }, 553 },
550 { /* 7450 2.1 */ 554 { /* 7450 2.1 */
551 .pvr_mask = 0xffffffff, 555 .pvr_mask = 0xffffffff,
@@ -556,7 +560,11 @@ struct cpu_spec cpu_specs[] = {
556 .icache_bsize = 32, 560 .icache_bsize = 32,
557 .dcache_bsize = 32, 561 .dcache_bsize = 32,
558 .num_pmcs = 6, 562 .num_pmcs = 6,
559 .cpu_setup = __setup_cpu_745x 563 .cpu_setup = __setup_cpu_745x,
564#ifdef CONFIG_OPROFILE
565 .oprofile_cpu_type = "ppc/7450",
566 .oprofile_model = &op_model_7450,
567#endif
560 }, 568 },
561 { /* 7450 2.3 and newer */ 569 { /* 7450 2.3 and newer */
562 .pvr_mask = 0xffff0000, 570 .pvr_mask = 0xffff0000,
@@ -567,7 +575,11 @@ struct cpu_spec cpu_specs[] = {
567 .icache_bsize = 32, 575 .icache_bsize = 32,
568 .dcache_bsize = 32, 576 .dcache_bsize = 32,
569 .num_pmcs = 6, 577 .num_pmcs = 6,
570 .cpu_setup = __setup_cpu_745x 578 .cpu_setup = __setup_cpu_745x,
579#ifdef CONFIG_OPROFILE
580 .oprofile_cpu_type = "ppc/7450",
581 .oprofile_model = &op_model_7450,
582#endif
571 }, 583 },
572 { /* 7455 rev 1.x */ 584 { /* 7455 rev 1.x */
573 .pvr_mask = 0xffffff00, 585 .pvr_mask = 0xffffff00,
@@ -578,7 +590,11 @@ struct cpu_spec cpu_specs[] = {
578 .icache_bsize = 32, 590 .icache_bsize = 32,
579 .dcache_bsize = 32, 591 .dcache_bsize = 32,
580 .num_pmcs = 6, 592 .num_pmcs = 6,
581 .cpu_setup = __setup_cpu_745x 593 .cpu_setup = __setup_cpu_745x,
594#ifdef CONFIG_OPROFILE
595 .oprofile_cpu_type = "ppc/7450",
596 .oprofile_model = &op_model_7450,
597#endif
582 }, 598 },
583 { /* 7455 rev 2.0 */ 599 { /* 7455 rev 2.0 */
584 .pvr_mask = 0xffffffff, 600 .pvr_mask = 0xffffffff,
@@ -589,7 +605,11 @@ struct cpu_spec cpu_specs[] = {
589 .icache_bsize = 32, 605 .icache_bsize = 32,
590 .dcache_bsize = 32, 606 .dcache_bsize = 32,
591 .num_pmcs = 6, 607 .num_pmcs = 6,
592 .cpu_setup = __setup_cpu_745x 608 .cpu_setup = __setup_cpu_745x,
609#ifdef CONFIG_OPROFILE
610 .oprofile_cpu_type = "ppc/7450",
611 .oprofile_model = &op_model_7450,
612#endif
593 }, 613 },
594 { /* 7455 others */ 614 { /* 7455 others */
595 .pvr_mask = 0xffff0000, 615 .pvr_mask = 0xffff0000,
@@ -600,7 +620,11 @@ struct cpu_spec cpu_specs[] = {
600 .icache_bsize = 32, 620 .icache_bsize = 32,
601 .dcache_bsize = 32, 621 .dcache_bsize = 32,
602 .num_pmcs = 6, 622 .num_pmcs = 6,
603 .cpu_setup = __setup_cpu_745x 623 .cpu_setup = __setup_cpu_745x,
624#ifdef CONFIG_OPROFILE
625 .oprofile_cpu_type = "ppc/7450",
626 .oprofile_model = &op_model_7450,
627#endif
604 }, 628 },
605 { /* 7447/7457 Rev 1.0 */ 629 { /* 7447/7457 Rev 1.0 */
606 .pvr_mask = 0xffffffff, 630 .pvr_mask = 0xffffffff,
@@ -611,7 +635,11 @@ struct cpu_spec cpu_specs[] = {
611 .icache_bsize = 32, 635 .icache_bsize = 32,
612 .dcache_bsize = 32, 636 .dcache_bsize = 32,
613 .num_pmcs = 6, 637 .num_pmcs = 6,
614 .cpu_setup = __setup_cpu_745x 638 .cpu_setup = __setup_cpu_745x,
639#ifdef CONFIG_OPROFILE
640 .oprofile_cpu_type = "ppc/7450",
641 .oprofile_model = &op_model_7450,
642#endif
615 }, 643 },
616 { /* 7447/7457 Rev 1.1 */ 644 { /* 7447/7457 Rev 1.1 */
617 .pvr_mask = 0xffffffff, 645 .pvr_mask = 0xffffffff,
@@ -622,7 +650,11 @@ struct cpu_spec cpu_specs[] = {
622 .icache_bsize = 32, 650 .icache_bsize = 32,
623 .dcache_bsize = 32, 651 .dcache_bsize = 32,
624 .num_pmcs = 6, 652 .num_pmcs = 6,
625 .cpu_setup = __setup_cpu_745x 653 .cpu_setup = __setup_cpu_745x,
654#ifdef CONFIG_OPROFILE
655 .oprofile_cpu_type = "ppc/7450",
656 .oprofile_model = &op_model_7450,
657#endif
626 }, 658 },
627 { /* 7447/7457 Rev 1.2 and later */ 659 { /* 7447/7457 Rev 1.2 and later */
628 .pvr_mask = 0xffff0000, 660 .pvr_mask = 0xffff0000,
@@ -633,7 +665,11 @@ struct cpu_spec cpu_specs[] = {
633 .icache_bsize = 32, 665 .icache_bsize = 32,
634 .dcache_bsize = 32, 666 .dcache_bsize = 32,
635 .num_pmcs = 6, 667 .num_pmcs = 6,
636 .cpu_setup = __setup_cpu_745x 668 .cpu_setup = __setup_cpu_745x,
669#ifdef CONFIG_OPROFILE
670 .oprofile_cpu_type = "ppc/7450",
671 .oprofile_model = &op_model_7450,
672#endif
637 }, 673 },
638 { /* 7447A */ 674 { /* 7447A */
639 .pvr_mask = 0xffff0000, 675 .pvr_mask = 0xffff0000,
@@ -644,7 +680,11 @@ struct cpu_spec cpu_specs[] = {
644 .icache_bsize = 32, 680 .icache_bsize = 32,
645 .dcache_bsize = 32, 681 .dcache_bsize = 32,
646 .num_pmcs = 6, 682 .num_pmcs = 6,
647 .cpu_setup = __setup_cpu_745x 683 .cpu_setup = __setup_cpu_745x,
684#ifdef CONFIG_OPROFILE
685 .oprofile_cpu_type = "ppc/7450",
686 .oprofile_model = &op_model_7450,
687#endif
648 }, 688 },
649 { /* 7448 */ 689 { /* 7448 */
650 .pvr_mask = 0xffff0000, 690 .pvr_mask = 0xffff0000,
@@ -655,7 +695,11 @@ struct cpu_spec cpu_specs[] = {
655 .icache_bsize = 32, 695 .icache_bsize = 32,
656 .dcache_bsize = 32, 696 .dcache_bsize = 32,
657 .num_pmcs = 6, 697 .num_pmcs = 6,
658 .cpu_setup = __setup_cpu_745x 698 .cpu_setup = __setup_cpu_745x,
699#ifdef CONFIG_OPROFILE
700 .oprofile_cpu_type = "ppc/7450",
701 .oprofile_model = &op_model_7450,
702#endif
659 }, 703 },
660 { /* 82xx (8240, 8245, 8260 are all 603e cores) */ 704 { /* 82xx (8240, 8245, 8260 are all 603e cores) */
661 .pvr_mask = 0x7fff0000, 705 .pvr_mask = 0x7fff0000,
@@ -979,6 +1023,10 @@ struct cpu_spec cpu_specs[] = {
979 .icache_bsize = 32, 1023 .icache_bsize = 32,
980 .dcache_bsize = 32, 1024 .dcache_bsize = 32,
981 .num_pmcs = 4, 1025 .num_pmcs = 4,
1026#ifdef CONFIG_OPROFILE
1027 .oprofile_cpu_type = "ppc/e500",
1028 .oprofile_model = &op_model_fsl_booke,
1029#endif
982 }, 1030 },
983 { /* e500v2 */ 1031 { /* e500v2 */
984 .pvr_mask = 0xffff0000, 1032 .pvr_mask = 0xffff0000,
@@ -992,6 +1040,10 @@ struct cpu_spec cpu_specs[] = {
992 .icache_bsize = 32, 1040 .icache_bsize = 32,
993 .dcache_bsize = 32, 1041 .dcache_bsize = 32,
994 .num_pmcs = 4, 1042 .num_pmcs = 4,
1043#ifdef CONFIG_OPROFILE
1044 .oprofile_cpu_type = "ppc/e500",
1045 .oprofile_model = &op_model_fsl_booke,
1046#endif
995 }, 1047 },
996#endif 1048#endif
997#if !CLASSIC_PPC 1049#if !CLASSIC_PPC
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 6359e364fe66..bf37ef2b3aac 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -466,16 +466,11 @@ SystemCall:
466 * by executing an altivec instruction. 466 * by executing an altivec instruction.
467 */ 467 */
468 . = 0xf00 468 . = 0xf00
469 b Trap_0f 469 b PerformanceMonitor
470 470
471 . = 0xf20 471 . = 0xf20
472 b AltiVecUnavailable 472 b AltiVecUnavailable
473 473
474Trap_0f:
475 EXCEPTION_PROLOG
476 addi r3,r1,STACK_FRAME_OVERHEAD
477 EXC_XFER_EE(0xf00, unknown_exception)
478
479/* 474/*
480 * Handle TLB miss for instruction on 603/603e. 475 * Handle TLB miss for instruction on 603/603e.
481 * Note: we get an alternate set of r0 - r3 to use automatically. 476 * Note: we get an alternate set of r0 - r3 to use automatically.
@@ -719,6 +714,11 @@ AltiVecUnavailable:
719#endif /* CONFIG_ALTIVEC */ 714#endif /* CONFIG_ALTIVEC */
720 EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) 715 EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
721 716
717PerformanceMonitor:
718 EXCEPTION_PROLOG
719 addi r3,r1,STACK_FRAME_OVERHEAD
720 EXC_XFER_STD(0xf00, performance_monitor_exception)
721
722#ifdef CONFIG_ALTIVEC 722#ifdef CONFIG_ALTIVEC
723/* Note that the AltiVec support is closely modeled after the FP 723/* Note that the AltiVec support is closely modeled after the FP
724 * support. Changes to one are likely to be applicable to the 724 * support. Changes to one are likely to be applicable to the
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 2d333cc84082..e6fb194fe537 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -43,8 +43,13 @@ static void dummy_perf(struct pt_regs *regs)
43 mtspr(SPRN_MMCR0, mmcr0); 43 mtspr(SPRN_MMCR0, mmcr0);
44} 44}
45#else 45#else
46/* Ensure exceptions are disabled */
46static void dummy_perf(struct pt_regs *regs) 47static void dummy_perf(struct pt_regs *regs)
47{ 48{
49 unsigned int mmcr0 = mfspr(SPRN_MMCR0);
50
51 mmcr0 &= ~(MMCR0_PMXE);
52 mtspr(SPRN_MMCR0, mmcr0);
48} 53}
49#endif 54#endif
50 55
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 76b579ca5230..6c793463d511 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -901,12 +901,10 @@ void altivec_unavailable_exception(struct pt_regs *regs)
901 die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); 901 die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
902} 902}
903 903
904#if defined(CONFIG_PPC64) || defined(CONFIG_E500)
905void performance_monitor_exception(struct pt_regs *regs) 904void performance_monitor_exception(struct pt_regs *regs)
906{ 905{
907 perf_irq(regs); 906 perf_irq(regs);
908} 907}
909#endif
910 908
911#ifdef CONFIG_8xx 909#ifdef CONFIG_8xx
912void SoftwareEmulation(struct pt_regs *regs) 910void SoftwareEmulation(struct pt_regs *regs)
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 0782d0cca89c..554cd7c75321 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -9,3 +9,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
9oprofile-y := $(DRIVER_OBJS) common.o 9oprofile-y := $(DRIVER_OBJS) common.o
10oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o 10oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
11oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o 11oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
12oprofile-$(CONFIG_PPC32) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index af2c05d20ba5..a370778b68dd 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -14,9 +14,6 @@
14 */ 14 */
15 15
16#include <linux/oprofile.h> 16#include <linux/oprofile.h>
17#ifndef __powerpc64__
18#include <linux/slab.h>
19#endif /* ! __powerpc64__ */
20#include <linux/init.h> 17#include <linux/init.h>
21#include <linux/smp.h> 18#include <linux/smp.h>
22#include <linux/errno.h> 19#include <linux/errno.h>
@@ -31,10 +28,6 @@ static struct op_powerpc_model *model;
31static struct op_counter_config ctr[OP_MAX_COUNTER]; 28static struct op_counter_config ctr[OP_MAX_COUNTER];
32static struct op_system_config sys; 29static struct op_system_config sys;
33 30
34#ifndef __powerpc64__
35static char *cpu_type;
36#endif /* ! __powerpc64__ */
37
38static void op_handle_interrupt(struct pt_regs *regs) 31static void op_handle_interrupt(struct pt_regs *regs)
39{ 32{
40 model->handle_interrupt(regs, ctr); 33 model->handle_interrupt(regs, ctr);
@@ -53,14 +46,7 @@ static int op_powerpc_setup(void)
53 model->reg_setup(ctr, &sys, model->num_counters); 46 model->reg_setup(ctr, &sys, model->num_counters);
54 47
55 /* Configure the registers on all cpus. */ 48 /* Configure the registers on all cpus. */
56#ifdef __powerpc64__
57 on_each_cpu(model->cpu_setup, NULL, 0, 1); 49 on_each_cpu(model->cpu_setup, NULL, 0, 1);
58#else /* __powerpc64__ */
59#if 0
60 /* FIXME: Make multi-cpu work */
61 on_each_cpu(model->reg_setup, NULL, 0, 1);
62#endif
63#endif /* __powerpc64__ */
64 50
65 return 0; 51 return 0;
66} 52}
@@ -95,7 +81,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
95{ 81{
96 int i; 82 int i;
97 83
98#ifdef __powerpc64__ 84#ifdef CONFIG_PPC64
99 /* 85 /*
100 * There is one mmcr0, mmcr1 and mmcra for setting the events for 86 * There is one mmcr0, mmcr1 and mmcra for setting the events for
101 * all of the counters. 87 * all of the counters.
@@ -103,7 +89,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
103 oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); 89 oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
104 oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); 90 oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
105 oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); 91 oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
106#endif /* __powerpc64__ */ 92#endif
107 93
108 for (i = 0; i < model->num_counters; ++i) { 94 for (i = 0; i < model->num_counters; ++i) {
109 struct dentry *dir; 95 struct dentry *dir;
@@ -115,65 +101,46 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
115 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); 101 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
116 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); 102 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
117 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); 103 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
118#ifdef __powerpc64__ 104
119 /* 105 /*
120 * We dont support per counter user/kernel selection, but 106 * Classic PowerPC doesn't support per-counter
121 * we leave the entries because userspace expects them 107 * control like this, but the options are
108 * expected, so they remain. For Freescale
109 * Book-E style performance monitors, we do
110 * support them.
122 */ 111 */
123#endif /* __powerpc64__ */
124 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); 112 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
125 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); 113 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
126 114
127#ifndef __powerpc64__
128 /* FIXME: Not sure if this is used */
129#endif /* ! __powerpc64__ */
130 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); 115 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
131 } 116 }
132 117
133 oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); 118 oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
134 oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); 119 oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
135#ifdef __powerpc64__ 120#ifdef CONFIG_PPC64
136 oprofilefs_create_ulong(sb, root, "backtrace_spinlocks", 121 oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
137 &sys.backtrace_spinlocks); 122 &sys.backtrace_spinlocks);
138#endif /* __powerpc64__ */ 123#endif
139 124
140 /* Default to tracing both kernel and user */ 125 /* Default to tracing both kernel and user */
141 sys.enable_kernel = 1; 126 sys.enable_kernel = 1;
142 sys.enable_user = 1; 127 sys.enable_user = 1;
143#ifdef __powerpc64__ 128#ifdef CONFIG_PPC64
144 /* Turn on backtracing through spinlocks by default */ 129 /* Turn on backtracing through spinlocks by default */
145 sys.backtrace_spinlocks = 1; 130 sys.backtrace_spinlocks = 1;
146#endif /* __powerpc64__ */ 131#endif
147 132
148 return 0; 133 return 0;
149} 134}
150 135
151int __init oprofile_arch_init(struct oprofile_operations *ops) 136int __init oprofile_arch_init(struct oprofile_operations *ops)
152{ 137{
153#ifndef __powerpc64__
154#ifdef CONFIG_FSL_BOOKE
155 model = &op_model_fsl_booke;
156#else
157 return -ENODEV;
158#endif
159
160 cpu_type = kmalloc(32, GFP_KERNEL);
161 if (NULL == cpu_type)
162 return -ENOMEM;
163
164 sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name);
165
166 model->num_counters = cur_cpu_spec->num_pmcs;
167
168 ops->cpu_type = cpu_type;
169#else /* __powerpc64__ */
170 if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type) 138 if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
171 return -ENODEV; 139 return -ENODEV;
172 model = cur_cpu_spec->oprofile_model; 140 model = cur_cpu_spec->oprofile_model;
173 model->num_counters = cur_cpu_spec->num_pmcs; 141 model->num_counters = cur_cpu_spec->num_pmcs;
174 142
175 ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; 143 ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
176#endif /* __powerpc64__ */
177 ops->create_files = op_powerpc_create_files; 144 ops->create_files = op_powerpc_create_files;
178 ops->setup = op_powerpc_setup; 145 ops->setup = op_powerpc_setup;
179 ops->shutdown = op_powerpc_shutdown; 146 ops->shutdown = op_powerpc_shutdown;
@@ -188,8 +155,4 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
188 155
189void oprofile_arch_exit(void) 156void oprofile_arch_exit(void)
190{ 157{
191#ifndef __powerpc64__
192 kfree(cpu_type);
193 cpu_type = NULL;
194#endif /* ! __powerpc64__ */
195} 158}
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
new file mode 100644
index 000000000000..32abfdbb0eb1
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -0,0 +1,206 @@
1/*
2 * oprofile/op_model_7450.c
3 *
4 * Freescale 745x/744x oprofile support, based on fsl_booke support
5 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
6 *
7 * Copyright (c) 2004 Freescale Semiconductor, Inc
8 *
9 * Author: Andy Fleming
10 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18#include <linux/oprofile.h>
19#include <linux/init.h>
20#include <linux/smp.h>
21#include <asm/ptrace.h>
22#include <asm/system.h>
23#include <asm/processor.h>
24#include <asm/cputable.h>
25#include <asm/page.h>
26#include <asm/pmc.h>
27#include <asm/oprofile_impl.h>
28
29static unsigned long reset_value[OP_MAX_COUNTER];
30
31static int oprofile_running;
32static u32 mmcr0_val, mmcr1_val, mmcr2_val;
33
34#define MMCR0_PMC1_SHIFT 6
35#define MMCR0_PMC2_SHIFT 0
36#define MMCR1_PMC3_SHIFT 27
37#define MMCR1_PMC4_SHIFT 22
38#define MMCR1_PMC5_SHIFT 17
39#define MMCR1_PMC6_SHIFT 11
40
41#define mmcr0_event1(event) \
42 ((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL)
43#define mmcr0_event2(event) \
44 ((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL)
45
46#define mmcr1_event3(event) \
47 ((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL)
48#define mmcr1_event4(event) \
49 ((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL)
50#define mmcr1_event5(event) \
51 ((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL)
52#define mmcr1_event6(event) \
53 ((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL)
54
55#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0)
56
57/* Unfreezes the counters on this CPU, enables the interrupt,
58 * enables the counters to trigger the interrupt, and sets the
59 * counters to only count when the mark bit is not set.
60 */
61static void pmc_start_ctrs(void)
62{
63 u32 mmcr0 = mfspr(SPRN_MMCR0);
64
65 mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0);
66 mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
67
68 mtspr(SPRN_MMCR0, mmcr0);
69}
70
71/* Disables the counters on this CPU, and freezes them */
72static void pmc_stop_ctrs(void)
73{
74 u32 mmcr0 = mfspr(SPRN_MMCR0);
75
76 mmcr0 |= MMCR0_FC;
77 mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE);
78
79 mtspr(SPRN_MMCR0, mmcr0);
80}
81
82/* Configures the counters on this CPU based on the global
83 * settings */
84static void fsl7450_cpu_setup(void *unused)
85{
86 /* freeze all counters */
87 pmc_stop_ctrs();
88
89 mtspr(SPRN_MMCR0, mmcr0_val);
90 mtspr(SPRN_MMCR1, mmcr1_val);
91 mtspr(SPRN_MMCR2, mmcr2_val);
92}
93
94#define NUM_CTRS 6
95
96/* Configures the global settings for the countes on all CPUs. */
97static void fsl7450_reg_setup(struct op_counter_config *ctr,
98 struct op_system_config *sys,
99 int num_ctrs)
100{
101 int i;
102
103 /* Our counters count up, and "count" refers to
104 * how much before the next interrupt, and we interrupt
105 * on overflow. So we calculate the starting value
106 * which will give us "count" until overflow.
107 * Then we set the events on the enabled counters */
108 for (i = 0; i < NUM_CTRS; ++i)
109 reset_value[i] = 0x80000000UL - ctr[i].count;
110
111 /* Set events for Counters 1 & 2 */
112 mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event)
113 | mmcr0_event2(ctr[1].event);
114
115 /* Setup user/kernel bits */
116 if (sys->enable_kernel)
117 mmcr0_val &= ~(MMCR0_FCS);
118
119 if (sys->enable_user)
120 mmcr0_val &= ~(MMCR0_FCP);
121
122 /* Set events for Counters 3-6 */
123 mmcr1_val = mmcr1_event3(ctr[2].event)
124 | mmcr1_event4(ctr[3].event)
125 | mmcr1_event5(ctr[4].event)
126 | mmcr1_event6(ctr[5].event);
127
128 mmcr2_val = 0;
129}
130
131/* Sets the counters on this CPU to the chosen values, and starts them */
132static void fsl7450_start(struct op_counter_config *ctr)
133{
134 int i;
135
136 mtmsr(mfmsr() | MSR_PMM);
137
138 for (i = 0; i < NUM_CTRS; ++i) {
139 if (ctr[i].enabled)
140 ctr_write(i, reset_value[i]);
141 else
142 ctr_write(i, 0);
143 }
144
145 /* Clear the freeze bit, and enable the interrupt.
146 * The counters won't actually start until the rfi clears
147 * the PMM bit */
148 pmc_start_ctrs();
149
150 oprofile_running = 1;
151}
152
153/* Stop the counters on this CPU */
154static void fsl7450_stop(void)
155{
156 /* freeze counters */
157 pmc_stop_ctrs();
158
159 oprofile_running = 0;
160
161 mb();
162}
163
164
165/* Handle the interrupt on this CPU, and log a sample for each
166 * event that triggered the interrupt */
167static void fsl7450_handle_interrupt(struct pt_regs *regs,
168 struct op_counter_config *ctr)
169{
170 unsigned long pc;
171 int is_kernel;
172 int val;
173 int i;
174
175 /* set the PMM bit (see comment below) */
176 mtmsr(mfmsr() | MSR_PMM);
177
178 pc = mfspr(SPRN_SIAR);
179 is_kernel = (pc >= KERNELBASE);
180
181 for (i = 0; i < NUM_CTRS; ++i) {
182 val = ctr_read(i);
183 if (val < 0) {
184 if (oprofile_running && ctr[i].enabled) {
185 oprofile_add_pc(pc, is_kernel, i);
186 ctr_write(i, reset_value[i]);
187 } else {
188 ctr_write(i, 0);
189 }
190 }
191 }
192
193 /* The freeze bit was set by the interrupt. */
194 /* Clear the freeze bit, and reenable the interrupt.
195 * The counters won't actually start until the rfi clears
196 * the PMM bit */
197 pmc_start_ctrs();
198}
199
200struct op_powerpc_model op_model_7450= {
201 .reg_setup = fsl7450_reg_setup,
202 .cpu_setup = fsl7450_cpu_setup,
203 .start = fsl7450_start,
204 .stop = fsl7450_stop,
205 .handle_interrupt = fsl7450_handle_interrupt,
206};