aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2013-12-12 10:52:48 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-12-16 08:37:52 -0500
commite28bb79d9935293a8eea5f3c771fde89db645ba7 (patch)
tree0d552a218e87c70ca55b5b103b5ef2a71477d400
parent55baa2f831ae4a41da9617ab9e7cef5ebc991ec9 (diff)
s390/perf,oprofile: Share sampling facility
Introduce reserve/release functions to share the sampling facility between perf and oprofile. Also improve error handling for the sampling facility support in perf. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/perf_event.h4
-rw-r--r--arch/s390/kernel/perf_cpum_sf.c17
-rw-r--r--arch/s390/kernel/perf_event.c30
-rw-r--r--arch/s390/oprofile/hwsampler.c7
-rw-r--r--arch/s390/oprofile/init.c23
5 files changed, 73 insertions, 8 deletions
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h
index b4eea25f379e..23d2dfa8201d 100644
--- a/arch/s390/include/asm/perf_event.h
+++ b/arch/s390/include/asm/perf_event.h
@@ -52,5 +52,9 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
52#define TEAR_REG(hwc) ((hwc)->last_tag) 52#define TEAR_REG(hwc) ((hwc)->last_tag)
53#define SAMPL_RATE(hwc) ((hwc)->event_base) 53#define SAMPL_RATE(hwc) ((hwc)->event_base)
54 54
55/* Perf hardware reserve and release functions */
56int perf_reserve_sampling(void);
57void perf_release_sampling(void);
58
55#endif /* CONFIG_64BIT */ 59#endif /* CONFIG_64BIT */
56#endif /* _ASM_S390_PERF_EVENT_H */ 60#endif /* _ASM_S390_PERF_EVENT_H */
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
index 52bf36ee91aa..ae5e0192160d 100644
--- a/arch/s390/kernel/perf_cpum_sf.c
+++ b/arch/s390/kernel/perf_cpum_sf.c
@@ -260,16 +260,12 @@ static int sf_disable(void)
260 260
261#define PMC_INIT 0 261#define PMC_INIT 0
262#define PMC_RELEASE 1 262#define PMC_RELEASE 1
263#define PMC_FAILURE 2
263static void setup_pmc_cpu(void *flags) 264static void setup_pmc_cpu(void *flags)
264{ 265{
265 int err; 266 int err;
266 struct cpu_hw_sf *cpusf = &__get_cpu_var(cpu_hw_sf); 267 struct cpu_hw_sf *cpusf = &__get_cpu_var(cpu_hw_sf);
267 268
268 /* XXX Improve error handling and pass a flag in the *flags
269 * variable to indicate failures. Alternatively, ignore
270 * (print) errors here and let the PMU functions fail if
271 * the per-cpu PMU_F_RESERVED flag is not.
272 */
273 err = 0; 269 err = 0;
274 switch (*((int *) flags)) { 270 switch (*((int *) flags)) {
275 case PMC_INIT: 271 case PMC_INIT:
@@ -299,6 +295,8 @@ static void setup_pmc_cpu(void *flags)
299 "setup_pmc_cpu: released: cpuhw=%p\n", cpusf); 295 "setup_pmc_cpu: released: cpuhw=%p\n", cpusf);
300 break; 296 break;
301 } 297 }
298 if (err)
299 *((int *) flags) |= PMC_FAILURE;
302} 300}
303 301
304static void release_pmc_hardware(void) 302static void release_pmc_hardware(void)
@@ -307,13 +305,22 @@ static void release_pmc_hardware(void)
307 305
308 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); 306 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
309 on_each_cpu(setup_pmc_cpu, &flags, 1); 307 on_each_cpu(setup_pmc_cpu, &flags, 1);
308 perf_release_sampling();
310} 309}
311 310
312static int reserve_pmc_hardware(void) 311static int reserve_pmc_hardware(void)
313{ 312{
314 int flags = PMC_INIT; 313 int flags = PMC_INIT;
314 int err;
315 315
316 err = perf_reserve_sampling();
317 if (err)
318 return err;
316 on_each_cpu(setup_pmc_cpu, &flags, 1); 319 on_each_cpu(setup_pmc_cpu, &flags, 1);
320 if (flags & PMC_FAILURE) {
321 release_pmc_hardware();
322 return -ENODEV;
323 }
317 irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); 324 irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
318 325
319 return 0; 326 return 0;
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
index b9843ba9829f..4edcdfa4894e 100644
--- a/arch/s390/kernel/perf_event.c
+++ b/arch/s390/kernel/perf_event.c
@@ -208,3 +208,33 @@ ssize_t cpumf_events_sysfs_show(struct device *dev,
208 return sprintf(page, "event=0x%04llx,name=%s\n", 208 return sprintf(page, "event=0x%04llx,name=%s\n",
209 pmu_attr->id, attr->attr.name); 209 pmu_attr->id, attr->attr.name);
210} 210}
211
212/* Reserve/release functions for sharing perf hardware */
213static DEFINE_SPINLOCK(perf_hw_owner_lock);
214static void *perf_sampling_owner;
215
216int perf_reserve_sampling(void)
217{
218 int err;
219
220 err = 0;
221 spin_lock(&perf_hw_owner_lock);
222 if (perf_sampling_owner) {
223 pr_warn("The sampling facility is already reserved by %p\n",
224 perf_sampling_owner);
225 err = -EBUSY;
226 } else
227 perf_sampling_owner = __builtin_return_address(0);
228 spin_unlock(&perf_hw_owner_lock);
229 return err;
230}
231EXPORT_SYMBOL(perf_reserve_sampling);
232
233void perf_release_sampling(void)
234{
235 spin_lock(&perf_hw_owner_lock);
236 WARN_ON(!perf_sampling_owner);
237 perf_sampling_owner = NULL;
238 spin_unlock(&perf_hw_owner_lock);
239}
240EXPORT_SYMBOL(perf_release_sampling);
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c
index bbca76ad6e1b..eb095874540d 100644
--- a/arch/s390/oprofile/hwsampler.c
+++ b/arch/s390/oprofile/hwsampler.c
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(hws_sem_oom);
41 41
42static unsigned char hws_flush_all; 42static unsigned char hws_flush_all;
43static unsigned int hws_oom; 43static unsigned int hws_oom;
44static unsigned int hws_alert;
44static struct workqueue_struct *hws_wq; 45static struct workqueue_struct *hws_wq;
45 46
46static unsigned int hws_state; 47static unsigned int hws_state;
@@ -182,6 +183,9 @@ static void hws_ext_handler(struct ext_code ext_code,
182 if (!(param32 & CPU_MF_INT_SF_MASK)) 183 if (!(param32 & CPU_MF_INT_SF_MASK))
183 return; 184 return;
184 185
186 if (!hws_alert)
187 return;
188
185 inc_irq_stat(IRQEXT_CMS); 189 inc_irq_stat(IRQEXT_CMS);
186 atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); 190 atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
187 191
@@ -941,6 +945,7 @@ int hwsampler_deallocate(void)
941 goto deallocate_exit; 945 goto deallocate_exit;
942 946
943 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); 947 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
948 hws_alert = 0;
944 deallocate_sdbt(); 949 deallocate_sdbt();
945 950
946 hws_state = HWS_DEALLOCATED; 951 hws_state = HWS_DEALLOCATED;
@@ -1055,6 +1060,7 @@ int hwsampler_shutdown(void)
1055 1060
1056 if (hws_state == HWS_STOPPED) { 1061 if (hws_state == HWS_STOPPED) {
1057 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); 1062 irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
1063 hws_alert = 0;
1058 deallocate_sdbt(); 1064 deallocate_sdbt();
1059 } 1065 }
1060 if (hws_wq) { 1066 if (hws_wq) {
@@ -1129,6 +1135,7 @@ start_all_exit:
1129 hws_oom = 1; 1135 hws_oom = 1;
1130 hws_flush_all = 0; 1136 hws_flush_all = 0;
1131 /* now let them in, 1407 CPUMF external interrupts */ 1137 /* now let them in, 1407 CPUMF external interrupts */
1138 hws_alert = 1;
1132 irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); 1139 irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
1133 1140
1134 return 0; 1141 return 0;
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
index 04e1b6a85362..9ffe645d5989 100644
--- a/arch/s390/oprofile/init.c
+++ b/arch/s390/oprofile/init.c
@@ -10,6 +10,7 @@
10 */ 10 */
11 11
12#include <linux/oprofile.h> 12#include <linux/oprofile.h>
13#include <linux/perf_event.h>
13#include <linux/init.h> 14#include <linux/init.h>
14#include <linux/errno.h> 15#include <linux/errno.h>
15#include <linux/fs.h> 16#include <linux/fs.h>
@@ -67,6 +68,21 @@ module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
67MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling" 68MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling"
68 "(report cpu_type \"timer\""); 69 "(report cpu_type \"timer\"");
69 70
71static int __oprofile_hwsampler_start(void)
72{
73 int retval;
74
75 retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
76 if (retval)
77 return retval;
78
79 retval = hwsampler_start_all(oprofile_hw_interval);
80 if (retval)
81 hwsampler_deallocate();
82
83 return retval;
84}
85
70static int oprofile_hwsampler_start(void) 86static int oprofile_hwsampler_start(void)
71{ 87{
72 int retval; 88 int retval;
@@ -76,13 +92,13 @@ static int oprofile_hwsampler_start(void)
76 if (!hwsampler_running) 92 if (!hwsampler_running)
77 return timer_ops.start(); 93 return timer_ops.start();
78 94
79 retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); 95 retval = perf_reserve_sampling();
80 if (retval) 96 if (retval)
81 return retval; 97 return retval;
82 98
83 retval = hwsampler_start_all(oprofile_hw_interval); 99 retval = __oprofile_hwsampler_start();
84 if (retval) 100 if (retval)
85 hwsampler_deallocate(); 101 perf_release_sampling();
86 102
87 return retval; 103 return retval;
88} 104}
@@ -96,6 +112,7 @@ static void oprofile_hwsampler_stop(void)
96 112
97 hwsampler_stop_all(); 113 hwsampler_stop_all();
98 hwsampler_deallocate(); 114 hwsampler_deallocate();
115 perf_release_sampling();
99 return; 116 return;
100} 117}
101 118