Merge tag 'platform-drivers-x86-v5.3-1' of git://git.infradead.org/linux-platform...
[sfrench/cifs-2.6.git] / arch / powerpc / oprofile / common.c
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
8  *
9  * Based on alpha version.
10  */
11
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>
21
22 static struct op_powerpc_model *model;
23
24 static struct op_counter_config ctr[OP_MAX_COUNTER];
25 static struct op_system_config sys;
26
27 static int op_per_cpu_rc;
28
29 static void op_handle_interrupt(struct pt_regs *regs)
30 {
31         model->handle_interrupt(regs, ctr);
32 }
33
34 static void op_powerpc_cpu_setup(void *dummy)
35 {
36         int ret;
37
38         ret = model->cpu_setup(ctr);
39
40         if (ret != 0)
41                 op_per_cpu_rc = ret;
42 }
43
44 static int op_powerpc_setup(void)
45 {
46         int err;
47
48         op_per_cpu_rc = 0;
49
50         /* Grab the hardware */
51         err = reserve_pmc_hardware(op_handle_interrupt);
52         if (err)
53                 return err;
54
55         /* Pre-compute the values to stuff in the hardware registers.  */
56         op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
57
58         if (op_per_cpu_rc)
59                 goto out;
60
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);
64
65 out:    if (op_per_cpu_rc) {
66                 /* error on setup release the performance counter hardware */
67                 release_pmc_hardware();
68         }
69
70         return op_per_cpu_rc;
71 }
72
73 static void op_powerpc_shutdown(void)
74 {
75         release_pmc_hardware();
76 }
77
78 static void op_powerpc_cpu_start(void *dummy)
79 {
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.
83          */
84         int ret;
85
86         ret = model->start(ctr);
87         if (ret != 0)
88                 op_per_cpu_rc = ret;
89 }
90
91 static int op_powerpc_start(void)
92 {
93         op_per_cpu_rc = 0;
94
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;
100         }
101         return -EIO; /* No start function is defined for this
102                         power architecture */
103 }
104
105 static inline void op_powerpc_cpu_stop(void *dummy)
106 {
107         model->stop();
108 }
109
110 static void op_powerpc_stop(void)
111 {
112         if (model->stop)
113                 on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
114         if (model->global_stop)
115                 model->global_stop();
116 }
117
118 static int op_powerpc_create_files(struct dentry *root)
119 {
120         int i;
121
122 #ifdef CONFIG_PPC64
123         /*
124          * There is one mmcr0, mmcr1 and mmcra for setting the events for
125          * all of the counters.
126          */
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.
137          *
138          * If the file does not exist, then the kernel only supports SPU
139          * cycle profiling, PPU event and cycle profiling.
140          */
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.
150                                  */
151 #endif
152 #endif
153
154         for (i = 0; i < model->num_counters; ++i) {
155                 struct dentry *dir;
156                 char buf[4];
157
158                 snprintf(buf, sizeof buf, "%d", i);
159                 dir = oprofilefs_mkdir(root, buf);
160
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);
164
165                 /*
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.
171                  */
172                 oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
173                 oprofilefs_create_ulong(dir, "user", &ctr[i].user);
174
175                 oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
176         }
177
178         oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel);
179         oprofilefs_create_ulong(root, "enable_user", &sys.enable_user);
180
181         /* Default to tracing both kernel and user */
182         sys.enable_kernel = 1;
183         sys.enable_user = 1;
184
185         return 0;
186 }
187
188 int __init oprofile_arch_init(struct oprofile_operations *ops)
189 {
190         if (!cur_cpu_spec->oprofile_cpu_type)
191                 return -ENODEV;
192
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;
223         }
224
225         model->num_counters = cur_cpu_spec->num_pmcs;
226
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;
234
235         printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
236                ops->cpu_type);
237
238         return 0;
239 }
240
241 void oprofile_arch_exit(void)
242 {
243 }