Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/oprofile/common.c
10817 views
1
/*
2
* PPC 64 oprofile support:
3
* Copyright (C) 2004 Anton Blanchard <[email protected]>, IBM
4
* PPC 32 oprofile support: (based on PPC 64 support)
5
* Copyright (C) Freescale Semiconductor, Inc 2004
6
* Author: Andy Fleming
7
*
8
* Based on alpha version.
9
*
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public License
12
* as published by the Free Software Foundation; either version
13
* 2 of the License, or (at your option) any later version.
14
*/
15
16
#include <linux/oprofile.h>
17
#include <linux/init.h>
18
#include <linux/smp.h>
19
#include <linux/errno.h>
20
#include <asm/ptrace.h>
21
#include <asm/system.h>
22
#include <asm/pmc.h>
23
#include <asm/cputable.h>
24
#include <asm/oprofile_impl.h>
25
#include <asm/firmware.h>
26
27
static struct op_powerpc_model *model;
28
29
static struct op_counter_config ctr[OP_MAX_COUNTER];
30
static struct op_system_config sys;
31
32
static int op_per_cpu_rc;
33
34
static void op_handle_interrupt(struct pt_regs *regs)
35
{
36
model->handle_interrupt(regs, ctr);
37
}
38
39
static void op_powerpc_cpu_setup(void *dummy)
40
{
41
int ret;
42
43
ret = model->cpu_setup(ctr);
44
45
if (ret != 0)
46
op_per_cpu_rc = ret;
47
}
48
49
static int op_powerpc_setup(void)
50
{
51
int err;
52
53
op_per_cpu_rc = 0;
54
55
/* Grab the hardware */
56
err = reserve_pmc_hardware(op_handle_interrupt);
57
if (err)
58
return err;
59
60
/* Pre-compute the values to stuff in the hardware registers. */
61
op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
62
63
if (op_per_cpu_rc)
64
goto out;
65
66
/* Configure the registers on all cpus. If an error occurs on one
67
* of the cpus, op_per_cpu_rc will be set to the error */
68
on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
69
70
out: if (op_per_cpu_rc) {
71
/* error on setup release the performance counter hardware */
72
release_pmc_hardware();
73
}
74
75
return op_per_cpu_rc;
76
}
77
78
static void op_powerpc_shutdown(void)
79
{
80
release_pmc_hardware();
81
}
82
83
static void op_powerpc_cpu_start(void *dummy)
84
{
85
/* If any of the cpus have return an error, set the
86
* global flag to the error so it can be returned
87
* to the generic OProfile caller.
88
*/
89
int ret;
90
91
ret = model->start(ctr);
92
if (ret != 0)
93
op_per_cpu_rc = ret;
94
}
95
96
static int op_powerpc_start(void)
97
{
98
op_per_cpu_rc = 0;
99
100
if (model->global_start)
101
return model->global_start(ctr);
102
if (model->start) {
103
on_each_cpu(op_powerpc_cpu_start, NULL, 1);
104
return op_per_cpu_rc;
105
}
106
return -EIO; /* No start function is defined for this
107
power architecture */
108
}
109
110
static inline void op_powerpc_cpu_stop(void *dummy)
111
{
112
model->stop();
113
}
114
115
static void op_powerpc_stop(void)
116
{
117
if (model->stop)
118
on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
119
if (model->global_stop)
120
model->global_stop();
121
}
122
123
static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
124
{
125
int i;
126
127
#ifdef CONFIG_PPC64
128
/*
129
* There is one mmcr0, mmcr1 and mmcra for setting the events for
130
* all of the counters.
131
*/
132
oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
133
oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
134
oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
135
#ifdef CONFIG_OPROFILE_CELL
136
/* create a file the user tool can check to see what level of profiling
137
* support exits with this kernel. Initialize bit mask to indicate
138
* what support the kernel has:
139
* bit 0 - Supports SPU event profiling in addition to PPU
140
* event and cycles; and SPU cycle profiling
141
* bits 1-31 - Currently unused.
142
*
143
* If the file does not exist, then the kernel only supports SPU
144
* cycle profiling, PPU event and cycle profiling.
145
*/
146
oprofilefs_create_ulong(sb, root, "cell_support", &sys.cell_support);
147
sys.cell_support = 0x1; /* Note, the user OProfile tool must check
148
* that this bit is set before attempting to
149
* user SPU event profiling. Older kernels
150
* will not have this file, hence the user
151
* tool is not allowed to do SPU event
152
* profiling on older kernels. Older kernels
153
* will accept SPU events but collected data
154
* is garbage.
155
*/
156
#endif
157
#endif
158
159
for (i = 0; i < model->num_counters; ++i) {
160
struct dentry *dir;
161
char buf[4];
162
163
snprintf(buf, sizeof buf, "%d", i);
164
dir = oprofilefs_mkdir(sb, root, buf);
165
166
oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
167
oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
168
oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
169
170
/*
171
* Classic PowerPC doesn't support per-counter
172
* control like this, but the options are
173
* expected, so they remain. For Freescale
174
* Book-E style performance monitors, we do
175
* support them.
176
*/
177
oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
178
oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
179
180
oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
181
}
182
183
oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
184
oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
185
186
/* Default to tracing both kernel and user */
187
sys.enable_kernel = 1;
188
sys.enable_user = 1;
189
190
return 0;
191
}
192
193
int __init oprofile_arch_init(struct oprofile_operations *ops)
194
{
195
if (!cur_cpu_spec->oprofile_cpu_type)
196
return -ENODEV;
197
198
if (firmware_has_feature(FW_FEATURE_ISERIES))
199
return -ENODEV;
200
201
switch (cur_cpu_spec->oprofile_type) {
202
#ifdef CONFIG_PPC_BOOK3S_64
203
#ifdef CONFIG_OPROFILE_CELL
204
case PPC_OPROFILE_CELL:
205
if (firmware_has_feature(FW_FEATURE_LPAR))
206
return -ENODEV;
207
model = &op_model_cell;
208
ops->sync_start = model->sync_start;
209
ops->sync_stop = model->sync_stop;
210
break;
211
#endif
212
case PPC_OPROFILE_RS64:
213
model = &op_model_rs64;
214
break;
215
case PPC_OPROFILE_POWER4:
216
model = &op_model_power4;
217
break;
218
case PPC_OPROFILE_PA6T:
219
model = &op_model_pa6t;
220
break;
221
#endif
222
#ifdef CONFIG_6xx
223
case PPC_OPROFILE_G4:
224
model = &op_model_7450;
225
break;
226
#endif
227
#if defined(CONFIG_FSL_EMB_PERFMON)
228
case PPC_OPROFILE_FSL_EMB:
229
model = &op_model_fsl_emb;
230
break;
231
#endif
232
default:
233
return -ENODEV;
234
}
235
236
model->num_counters = cur_cpu_spec->num_pmcs;
237
238
ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
239
ops->create_files = op_powerpc_create_files;
240
ops->setup = op_powerpc_setup;
241
ops->shutdown = op_powerpc_shutdown;
242
ops->start = op_powerpc_start;
243
ops->stop = op_powerpc_stop;
244
ops->backtrace = op_powerpc_backtrace;
245
246
printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
247
ops->cpu_type);
248
249
return 0;
250
}
251
252
void oprofile_arch_exit(void)
253
{
254
}
255
256