aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/oprofile
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/oprofile')
-rw-r--r--arch/mips/oprofile/Kconfig23
-rw-r--r--arch/mips/oprofile/Makefile15
-rw-r--r--arch/mips/oprofile/common.c106
-rw-r--r--arch/mips/oprofile/op_impl.h37
-rw-r--r--arch/mips/oprofile/op_model_rm9000.c137
5 files changed, 318 insertions, 0 deletions
diff --git a/arch/mips/oprofile/Kconfig b/arch/mips/oprofile/Kconfig
new file mode 100644
index 000000000000..19d37730b664
--- /dev/null
+++ b/arch/mips/oprofile/Kconfig
@@ -0,0 +1,23 @@
1
2menu "Profiling support"
3 depends on EXPERIMENTAL
4
5config PROFILING
6 bool "Profiling support (EXPERIMENTAL)"
7 help
8 Say Y here to enable the extended profiling support mechanisms used
9 by profilers such as OProfile.
10
11
12config OPROFILE
13 tristate "OProfile system profiling (EXPERIMENTAL)"
14 depends on PROFILING
15 help
16 OProfile is a profiling system capable of profiling the
17 whole system, include the kernel, kernel modules, libraries,
18 and applications.
19
20 If unsure, say N.
21
22endmenu
23
diff --git a/arch/mips/oprofile/Makefile b/arch/mips/oprofile/Makefile
new file mode 100644
index 000000000000..354261d37d62
--- /dev/null
+++ b/arch/mips/oprofile/Makefile
@@ -0,0 +1,15 @@
1EXTRA_CFLAGS := -Werror
2
3obj-$(CONFIG_OPROFILE) += oprofile.o
4
5DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
6 oprof.o cpu_buffer.o buffer_sync.o \
7 event_buffer.o oprofile_files.o \
8 oprofilefs.o oprofile_stats.o \
9 timer_int.o )
10
11oprofile-y := $(DRIVER_OBJS) common.o
12
13oprofile-$(CONFIG_CPU_MIPS32) += op_model_mipsxx.o
14oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o
15oprofile-$(CONFIG_CPU_RM9000) += op_model_rm9000.o
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
new file mode 100644
index 000000000000..ab65ce3d471a
--- /dev/null
+++ b/arch/mips/oprofile/common.c
@@ -0,0 +1,106 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2004 by Ralf Baechle
7 */
8#include <linux/errno.h>
9#include <linux/init.h>
10#include <linux/oprofile.h>
11#include <linux/smp.h>
12#include <asm/cpu-info.h>
13
14#include "op_impl.h"
15
16extern struct op_mips_model op_model_mipsxx __attribute__((weak));
17extern struct op_mips_model op_model_rm9000 __attribute__((weak));
18
19static struct op_mips_model *model;
20
21static struct op_counter_config ctr[20];
22
23static int op_mips_setup(void)
24{
25 /* Pre-compute the values to stuff in the hardware registers. */
26 model->reg_setup(ctr);
27
28 /* Configure the registers on all cpus. */
29 on_each_cpu(model->cpu_setup, 0, 0, 1);
30
31 return 0;
32}
33
34static int op_mips_create_files(struct super_block * sb, struct dentry * root)
35{
36 int i;
37
38 for (i = 0; i < model->num_counters; ++i) {
39 struct dentry *dir;
40 char buf[3];
41
42 snprintf(buf, sizeof buf, "%d", i);
43 dir = oprofilefs_mkdir(sb, root, buf);
44
45 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
46 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
47 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
48 /* Dummies. */
49 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
50 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
51 oprofilefs_create_ulong(sb, dir, "exl", &ctr[i].exl);
52 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
53 }
54
55 return 0;
56}
57
58static int op_mips_start(void)
59{
60 on_each_cpu(model->cpu_start, NULL, 0, 1);
61
62 return 0;
63}
64
65static void op_mips_stop(void)
66{
67 /* Disable performance monitoring for all counters. */
68 on_each_cpu(model->cpu_stop, NULL, 0, 1);
69}
70
71void __init oprofile_arch_init(struct oprofile_operations *ops)
72{
73 struct op_mips_model *lmodel = NULL;
74
75 switch (current_cpu_data.cputype) {
76 case CPU_24K:
77 lmodel = &op_model_mipsxx;
78 break;
79
80 case CPU_RM9000:
81 lmodel = &op_model_rm9000;
82 break;
83 };
84
85 if (!lmodel)
86 return;
87
88 if (lmodel->init())
89 return;
90
91 model = lmodel;
92
93 ops->create_files = op_mips_create_files;
94 ops->setup = op_mips_setup;
95 ops->start = op_mips_start;
96 ops->stop = op_mips_stop;
97 ops->cpu_type = lmodel->cpu_type;
98
99 printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
100 lmodel->cpu_type);
101}
102
103void oprofile_arch_exit(void)
104{
105 model->exit();
106}
diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h
new file mode 100644
index 000000000000..9f5cdff041be
--- /dev/null
+++ b/arch/mips/oprofile/op_impl.h
@@ -0,0 +1,37 @@
1/**
2 * @file arch/alpha/oprofile/op_impl.h
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author Richard Henderson <rth@twiddle.net>
8 */
9
10#ifndef OP_IMPL_H
11#define OP_IMPL_H 1
12
13/* Per-counter configuration as set via oprofilefs. */
14struct op_counter_config {
15 unsigned long enabled;
16 unsigned long event;
17 unsigned long count;
18 /* Dummies because I am too lazy to hack the userspace tools. */
19 unsigned long kernel;
20 unsigned long user;
21 unsigned long exl;
22 unsigned long unit_mask;
23};
24
25/* Per-architecture configury and hooks. */
26struct op_mips_model {
27 void (*reg_setup) (struct op_counter_config *);
28 void (*cpu_setup) (void * dummy);
29 int (*init)(void);
30 void (*exit)(void);
31 void (*cpu_start)(void *args);
32 void (*cpu_stop)(void *args);
33 char *cpu_type;
34 unsigned char num_counters;
35};
36
37#endif
diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c
new file mode 100644
index 000000000000..bee47793cb1a
--- /dev/null
+++ b/arch/mips/oprofile/op_model_rm9000.c
@@ -0,0 +1,137 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2004 by Ralf Baechle
7 */
8#include <linux/oprofile.h>
9#include <linux/interrupt.h>
10#include <linux/smp.h>
11
12#include "op_impl.h"
13
14#define RM9K_COUNTER1_EVENT(event) ((event) << 0)
15#define RM9K_COUNTER1_SUPERVISOR (1ULL << 7)
16#define RM9K_COUNTER1_KERNEL (1ULL << 8)
17#define RM9K_COUNTER1_USER (1ULL << 9)
18#define RM9K_COUNTER1_ENABLE (1ULL << 10)
19#define RM9K_COUNTER1_OVERFLOW (1ULL << 15)
20
21#define RM9K_COUNTER2_EVENT(event) ((event) << 16)
22#define RM9K_COUNTER2_SUPERVISOR (1ULL << 23)
23#define RM9K_COUNTER2_KERNEL (1ULL << 24)
24#define RM9K_COUNTER2_USER (1ULL << 25)
25#define RM9K_COUNTER2_ENABLE (1ULL << 26)
26#define RM9K_COUNTER2_OVERFLOW (1ULL << 31)
27
28extern unsigned int rm9000_perfcount_irq;
29
30static struct rm9k_register_config {
31 unsigned int control;
32 unsigned int reset_counter1;
33 unsigned int reset_counter2;
34} reg;
35
36/* Compute all of the registers in preparation for enabling profiling. */
37
38static void rm9000_reg_setup(struct op_counter_config *ctr)
39{
40 unsigned int control = 0;
41
42 /* Compute the performance counter control word. */
43 /* For now count kernel and user mode */
44 if (ctr[0].enabled)
45 control |= RM9K_COUNTER1_EVENT(ctr[0].event) |
46 RM9K_COUNTER1_KERNEL |
47 RM9K_COUNTER1_USER |
48 RM9K_COUNTER1_ENABLE;
49 if (ctr[1].enabled)
50 control |= RM9K_COUNTER2_EVENT(ctr[1].event) |
51 RM9K_COUNTER2_KERNEL |
52 RM9K_COUNTER2_USER |
53 RM9K_COUNTER2_ENABLE;
54 reg.control = control;
55
56 reg.reset_counter1 = 0x80000000 - ctr[0].count;
57 reg.reset_counter2 = 0x80000000 - ctr[1].count;
58}
59
60/* Program all of the registers in preparation for enabling profiling. */
61
62static void rm9000_cpu_setup (void *args)
63{
64 uint64_t perfcount;
65
66 perfcount = ((uint64_t) reg.reset_counter2 << 32) | reg.reset_counter1;
67 write_c0_perfcount(perfcount);
68}
69
70static void rm9000_cpu_start(void *args)
71{
72 /* Start all counters on current CPU */
73 write_c0_perfcontrol(reg.control);
74}
75
76static void rm9000_cpu_stop(void *args)
77{
78 /* Stop all counters on current CPU */
79 write_c0_perfcontrol(0);
80}
81
82static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id,
83 struct pt_regs *regs)
84{
85 unsigned int control = read_c0_perfcontrol();
86 uint32_t counter1, counter2;
87 uint64_t counters;
88
89 /*
90 * RM9000 combines two 32-bit performance counters into a single
91 * 64-bit coprocessor zero register. To avoid a race updating the
92 * registers we need to stop the counters while we're messing with
93 * them ...
94 */
95 write_c0_perfcontrol(0);
96
97 counters = read_c0_perfcount();
98 counter1 = counters;
99 counter2 = counters >> 32;
100
101 if (control & RM9K_COUNTER1_OVERFLOW) {
102 oprofile_add_sample(regs, 0);
103 counter1 = reg.reset_counter1;
104 }
105 if (control & RM9K_COUNTER2_OVERFLOW) {
106 oprofile_add_sample(regs, 1);
107 counter2 = reg.reset_counter2;
108 }
109
110 counters = ((uint64_t)counter2 << 32) | counter1;
111 write_c0_perfcount(counters);
112 write_c0_perfcontrol(reg.control);
113
114 return IRQ_HANDLED;
115}
116
117static int rm9000_init(void)
118{
119 return request_irq(rm9000_perfcount_irq, rm9000_perfcount_handler,
120 0, "Perfcounter", NULL);
121}
122
123static void rm9000_exit(void)
124{
125 free_irq(rm9000_perfcount_irq, NULL);
126}
127
128struct op_mips_model op_model_rm9000 = {
129 .reg_setup = rm9000_reg_setup,
130 .cpu_setup = rm9000_cpu_setup,
131 .init = rm9000_init,
132 .exit = rm9000_exit,
133 .cpu_start = rm9000_cpu_start,
134 .cpu_stop = rm9000_cpu_stop,
135 .cpu_type = "mips/rm9000",
136 .num_counters = 2
137};