WIP FPC-III support
[linux/fpc-iii.git] / arch / powerpc / oprofile / common.c
blob0fb528c2b3a13066917a7a4de5f450a65477fe00
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PPC 64 oprofile support:
4 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
5 * PPC 32 oprofile support: (based on PPC 64 support)
6 * Copyright (C) Freescale Semiconductor, Inc 2004
7 * Author: Andy Fleming
9 * Based on alpha version.
12 #include <linux/oprofile.h>
13 #include <linux/init.h>
14 #include <linux/smp.h>
15 #include <linux/errno.h>
16 #include <asm/ptrace.h>
17 #include <asm/pmc.h>
18 #include <asm/cputable.h>
19 #include <asm/oprofile_impl.h>
20 #include <asm/firmware.h>
22 static struct op_powerpc_model *model;
24 static struct op_counter_config ctr[OP_MAX_COUNTER];
25 static struct op_system_config sys;
27 static int op_per_cpu_rc;
29 static void op_handle_interrupt(struct pt_regs *regs)
31 model->handle_interrupt(regs, ctr);
34 static void op_powerpc_cpu_setup(void *dummy)
36 int ret;
38 ret = model->cpu_setup(ctr);
40 if (ret != 0)
41 op_per_cpu_rc = ret;
44 static int op_powerpc_setup(void)
46 int err;
48 op_per_cpu_rc = 0;
50 /* Grab the hardware */
51 err = reserve_pmc_hardware(op_handle_interrupt);
52 if (err)
53 return err;
55 /* Pre-compute the values to stuff in the hardware registers. */
56 op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
58 if (op_per_cpu_rc)
59 goto out;
61 /* Configure the registers on all cpus. If an error occurs on one
62 * of the cpus, op_per_cpu_rc will be set to the error */
63 on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
65 out: if (op_per_cpu_rc) {
66 /* error on setup release the performance counter hardware */
67 release_pmc_hardware();
70 return op_per_cpu_rc;
73 static void op_powerpc_shutdown(void)
75 release_pmc_hardware();
78 static void op_powerpc_cpu_start(void *dummy)
80 /* If any of the cpus have return an error, set the
81 * global flag to the error so it can be returned
82 * to the generic OProfile caller.
84 int ret;
86 ret = model->start(ctr);
87 if (ret != 0)
88 op_per_cpu_rc = ret;
91 static int op_powerpc_start(void)
93 op_per_cpu_rc = 0;
95 if (model->global_start)
96 return model->global_start(ctr);
97 if (model->start) {
98 on_each_cpu(op_powerpc_cpu_start, NULL, 1);
99 return op_per_cpu_rc;
101 return -EIO; /* No start function is defined for this
102 power architecture */
105 static inline void op_powerpc_cpu_stop(void *dummy)
107 model->stop();
110 static void op_powerpc_stop(void)
112 if (model->stop)
113 on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
114 if (model->global_stop)
115 model->global_stop();
118 static int op_powerpc_create_files(struct dentry *root)
120 int i;
122 #ifdef CONFIG_PPC64
124 * There is one mmcr0, mmcr1 and mmcra for setting the events for
125 * all of the counters.
127 oprofilefs_create_ulong(root, "mmcr0", &sys.mmcr0);
128 oprofilefs_create_ulong(root, "mmcr1", &sys.mmcr1);
129 oprofilefs_create_ulong(root, "mmcra", &sys.mmcra);
130 #ifdef CONFIG_OPROFILE_CELL
131 /* create a file the user tool can check to see what level of profiling
132 * support exits with this kernel. Initialize bit mask to indicate
133 * what support the kernel has:
134 * bit 0 - Supports SPU event profiling in addition to PPU
135 * event and cycles; and SPU cycle profiling
136 * bits 1-31 - Currently unused.
138 * If the file does not exist, then the kernel only supports SPU
139 * cycle profiling, PPU event and cycle profiling.
141 oprofilefs_create_ulong(root, "cell_support", &sys.cell_support);
142 sys.cell_support = 0x1; /* Note, the user OProfile tool must check
143 * that this bit is set before attempting to
144 * user SPU event profiling. Older kernels
145 * will not have this file, hence the user
146 * tool is not allowed to do SPU event
147 * profiling on older kernels. Older kernels
148 * will accept SPU events but collected data
149 * is garbage.
151 #endif
152 #endif
154 for (i = 0; i < model->num_counters; ++i) {
155 struct dentry *dir;
156 char buf[4];
158 snprintf(buf, sizeof buf, "%d", i);
159 dir = oprofilefs_mkdir(root, buf);
161 oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
162 oprofilefs_create_ulong(dir, "event", &ctr[i].event);
163 oprofilefs_create_ulong(dir, "count", &ctr[i].count);
166 * Classic PowerPC doesn't support per-counter
167 * control like this, but the options are
168 * expected, so they remain. For Freescale
169 * Book-E style performance monitors, we do
170 * support them.
172 oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
173 oprofilefs_create_ulong(dir, "user", &ctr[i].user);
175 oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
178 oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel);
179 oprofilefs_create_ulong(root, "enable_user", &sys.enable_user);
181 /* Default to tracing both kernel and user */
182 sys.enable_kernel = 1;
183 sys.enable_user = 1;
185 return 0;
188 int __init oprofile_arch_init(struct oprofile_operations *ops)
190 if (!cur_cpu_spec->oprofile_cpu_type)
191 return -ENODEV;
193 switch (cur_cpu_spec->oprofile_type) {
194 #ifdef CONFIG_PPC_BOOK3S_64
195 #ifdef CONFIG_OPROFILE_CELL
196 case PPC_OPROFILE_CELL:
197 if (firmware_has_feature(FW_FEATURE_LPAR))
198 return -ENODEV;
199 model = &op_model_cell;
200 ops->sync_start = model->sync_start;
201 ops->sync_stop = model->sync_stop;
202 break;
203 #endif
204 case PPC_OPROFILE_POWER4:
205 model = &op_model_power4;
206 break;
207 case PPC_OPROFILE_PA6T:
208 model = &op_model_pa6t;
209 break;
210 #endif
211 #ifdef CONFIG_PPC_BOOK3S_32
212 case PPC_OPROFILE_G4:
213 model = &op_model_7450;
214 break;
215 #endif
216 #if defined(CONFIG_FSL_EMB_PERFMON)
217 case PPC_OPROFILE_FSL_EMB:
218 model = &op_model_fsl_emb;
219 break;
220 #endif
221 default:
222 return -ENODEV;
225 model->num_counters = cur_cpu_spec->num_pmcs;
227 ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
228 ops->create_files = op_powerpc_create_files;
229 ops->setup = op_powerpc_setup;
230 ops->shutdown = op_powerpc_shutdown;
231 ops->start = op_powerpc_start;
232 ops->stop = op_powerpc_stop;
233 ops->backtrace = op_powerpc_backtrace;
235 printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
236 ops->cpu_type);
238 return 0;
241 void oprofile_arch_exit(void)