aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-09 20:33:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-09 20:33:44 -0400
commitc23190c0bf1236e1eb5521a8b10d0102fbc1338c (patch)
treeeb23225a121fb56a58d69d34e7338bfe81ede644
parentfc335c1b68c68f626f07f1819e57d112d666bbba (diff)
parent45ed695ac10a23cb4e60a3e0b68b3f21a8670670 (diff)
Merge tag 'trace-ipi-tracepoints' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull IPI tracepoints for ARM from Steven Rostedt: "Nicolas Pitre added generic tracepoints for tracing IPIs and updated the arm and arm64 architectures. It required some minor updates to the generic tracepoint system, so it had to wait for me to implement them" * tag 'trace-ipi-tracepoints' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ARM64: add IPI tracepoints ARM: add IPI tracepoints tracepoint: add generic tracepoint definitions for IPI tracing tracing: Do not do anything special with tracepoint_string when tracing is disabled
-rw-r--r--arch/arm/kernel/smp.c70
-rw-r--r--arch/arm64/kernel/smp.c65
-rw-r--r--include/linux/ftrace_event.h34
-rw-r--r--include/linux/tracepoint.h44
-rw-r--r--include/trace/events/ipi.h89
5 files changed, 214 insertions, 88 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 7c4fada440f0..9388a3d479e1 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -47,6 +47,9 @@
47#include <asm/mach/arch.h> 47#include <asm/mach/arch.h>
48#include <asm/mpu.h> 48#include <asm/mpu.h>
49 49
50#define CREATE_TRACE_POINTS
51#include <trace/events/ipi.h>
52
50/* 53/*
51 * as from 2.5, kernels no longer have an init_tasks structure 54 * as from 2.5, kernels no longer have an init_tasks structure
52 * so we need some other way of telling a new secondary core 55 * so we need some other way of telling a new secondary core
@@ -430,38 +433,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
430 } 433 }
431} 434}
432 435
433static void (*smp_cross_call)(const struct cpumask *, unsigned int); 436static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
434 437
435void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 438void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
436{ 439{
437 if (!smp_cross_call) 440 if (!__smp_cross_call)
438 smp_cross_call = fn; 441 __smp_cross_call = fn;
439}
440
441void arch_send_call_function_ipi_mask(const struct cpumask *mask)
442{
443 smp_cross_call(mask, IPI_CALL_FUNC);
444}
445
446void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
447{
448 smp_cross_call(mask, IPI_WAKEUP);
449}
450
451void arch_send_call_function_single_ipi(int cpu)
452{
453 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
454} 442}
455 443
456#ifdef CONFIG_IRQ_WORK 444static const char *ipi_types[NR_IPI] __tracepoint_string = {
457void arch_irq_work_raise(void)
458{
459 if (is_smp())
460 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
461}
462#endif
463
464static const char *ipi_types[NR_IPI] = {
465#define S(x,s) [x] = s 445#define S(x,s) [x] = s
466 S(IPI_WAKEUP, "CPU wakeup interrupts"), 446 S(IPI_WAKEUP, "CPU wakeup interrupts"),
467 S(IPI_TIMER, "Timer broadcast interrupts"), 447 S(IPI_TIMER, "Timer broadcast interrupts"),
@@ -473,6 +453,12 @@ static const char *ipi_types[NR_IPI] = {
473 S(IPI_COMPLETION, "completion interrupts"), 453 S(IPI_COMPLETION, "completion interrupts"),
474}; 454};
475 455
456static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
457{
458 trace_ipi_raise(target, ipi_types[ipinr]);
459 __smp_cross_call(target, ipinr);
460}
461
476void show_ipi_list(struct seq_file *p, int prec) 462void show_ipi_list(struct seq_file *p, int prec)
477{ 463{
478 unsigned int cpu, i; 464 unsigned int cpu, i;
@@ -499,6 +485,29 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
499 return sum; 485 return sum;
500} 486}
501 487
488void arch_send_call_function_ipi_mask(const struct cpumask *mask)
489{
490 smp_cross_call(mask, IPI_CALL_FUNC);
491}
492
493void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
494{
495 smp_cross_call(mask, IPI_WAKEUP);
496}
497
498void arch_send_call_function_single_ipi(int cpu)
499{
500 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
501}
502
503#ifdef CONFIG_IRQ_WORK
504void arch_irq_work_raise(void)
505{
506 if (is_smp())
507 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
508}
509#endif
510
502#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 511#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
503void tick_broadcast(const struct cpumask *mask) 512void tick_broadcast(const struct cpumask *mask)
504{ 513{
@@ -556,8 +565,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
556 unsigned int cpu = smp_processor_id(); 565 unsigned int cpu = smp_processor_id();
557 struct pt_regs *old_regs = set_irq_regs(regs); 566 struct pt_regs *old_regs = set_irq_regs(regs);
558 567
559 if (ipinr < NR_IPI) 568 if ((unsigned)ipinr < NR_IPI) {
569 trace_ipi_entry(ipi_types[ipinr]);
560 __inc_irq_stat(cpu, ipi_irqs[ipinr]); 570 __inc_irq_stat(cpu, ipi_irqs[ipinr]);
571 }
561 572
562 switch (ipinr) { 573 switch (ipinr) {
563 case IPI_WAKEUP: 574 case IPI_WAKEUP:
@@ -612,6 +623,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
612 cpu, ipinr); 623 cpu, ipinr);
613 break; 624 break;
614 } 625 }
626
627 if ((unsigned)ipinr < NR_IPI)
628 trace_ipi_exit(ipi_types[ipinr]);
615 set_irq_regs(old_regs); 629 set_irq_regs(old_regs);
616} 630}
617 631
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 3e2f5ebbf63e..474339718105 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -51,6 +51,9 @@
51#include <asm/tlbflush.h> 51#include <asm/tlbflush.h>
52#include <asm/ptrace.h> 52#include <asm/ptrace.h>
53 53
54#define CREATE_TRACE_POINTS
55#include <trace/events/ipi.h>
56
54/* 57/*
55 * as from 2.5, kernels no longer have an init_tasks structure 58 * as from 2.5, kernels no longer have an init_tasks structure
56 * so we need some other way of telling a new secondary core 59 * so we need some other way of telling a new secondary core
@@ -313,8 +316,6 @@ void __init smp_prepare_boot_cpu(void)
313 set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 316 set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
314} 317}
315 318
316static void (*smp_cross_call)(const struct cpumask *, unsigned int);
317
318/* 319/*
319 * Enumerate the possible CPU set from the device tree and build the 320 * Enumerate the possible CPU set from the device tree and build the
320 * cpu logical map array containing MPIDR values related to logical 321 * cpu logical map array containing MPIDR values related to logical
@@ -469,32 +470,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
469 } 470 }
470} 471}
471 472
473static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
472 474
473void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 475void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
474{ 476{
475 smp_cross_call = fn; 477 __smp_cross_call = fn;
476} 478}
477 479
478void arch_send_call_function_ipi_mask(const struct cpumask *mask) 480static const char *ipi_types[NR_IPI] __tracepoint_string = {
479{ 481#define S(x,s) [x] = s
480 smp_cross_call(mask, IPI_CALL_FUNC);
481}
482
483void arch_send_call_function_single_ipi(int cpu)
484{
485 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
486}
487
488#ifdef CONFIG_IRQ_WORK
489void arch_irq_work_raise(void)
490{
491 if (smp_cross_call)
492 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
493}
494#endif
495
496static const char *ipi_types[NR_IPI] = {
497#define S(x,s) [x - IPI_RESCHEDULE] = s
498 S(IPI_RESCHEDULE, "Rescheduling interrupts"), 482 S(IPI_RESCHEDULE, "Rescheduling interrupts"),
499 S(IPI_CALL_FUNC, "Function call interrupts"), 483 S(IPI_CALL_FUNC, "Function call interrupts"),
500 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 484 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
@@ -503,12 +487,18 @@ static const char *ipi_types[NR_IPI] = {
503 S(IPI_IRQ_WORK, "IRQ work interrupts"), 487 S(IPI_IRQ_WORK, "IRQ work interrupts"),
504}; 488};
505 489
490static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
491{
492 trace_ipi_raise(target, ipi_types[ipinr]);
493 __smp_cross_call(target, ipinr);
494}
495
506void show_ipi_list(struct seq_file *p, int prec) 496void show_ipi_list(struct seq_file *p, int prec)
507{ 497{
508 unsigned int cpu, i; 498 unsigned int cpu, i;
509 499
510 for (i = 0; i < NR_IPI; i++) { 500 for (i = 0; i < NR_IPI; i++) {
511 seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE, 501 seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
512 prec >= 4 ? " " : ""); 502 prec >= 4 ? " " : "");
513 for_each_online_cpu(cpu) 503 for_each_online_cpu(cpu)
514 seq_printf(p, "%10u ", 504 seq_printf(p, "%10u ",
@@ -528,6 +518,24 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
528 return sum; 518 return sum;
529} 519}
530 520
521void arch_send_call_function_ipi_mask(const struct cpumask *mask)
522{
523 smp_cross_call(mask, IPI_CALL_FUNC);
524}
525
526void arch_send_call_function_single_ipi(int cpu)
527{
528 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
529}
530
531#ifdef CONFIG_IRQ_WORK
532void arch_irq_work_raise(void)
533{
534 if (__smp_cross_call)
535 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
536}
537#endif
538
531static DEFINE_RAW_SPINLOCK(stop_lock); 539static DEFINE_RAW_SPINLOCK(stop_lock);
532 540
533/* 541/*
@@ -559,8 +567,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
559 unsigned int cpu = smp_processor_id(); 567 unsigned int cpu = smp_processor_id();
560 struct pt_regs *old_regs = set_irq_regs(regs); 568 struct pt_regs *old_regs = set_irq_regs(regs);
561 569
562 if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI) 570 if ((unsigned)ipinr < NR_IPI) {
563 __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]); 571 trace_ipi_entry(ipi_types[ipinr]);
572 __inc_irq_stat(cpu, ipi_irqs[ipinr]);
573 }
564 574
565 switch (ipinr) { 575 switch (ipinr) {
566 case IPI_RESCHEDULE: 576 case IPI_RESCHEDULE:
@@ -605,6 +615,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
605 pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 615 pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
606 break; 616 break;
607 } 617 }
618
619 if ((unsigned)ipinr < NR_IPI)
620 trace_ipi_exit(ipi_types[ipinr]);
608 set_irq_regs(old_regs); 621 set_irq_regs(old_regs);
609} 622}
610 623
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 06c6faa9e5cc..28672e87e910 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -571,40 +571,6 @@ do { \
571 __trace_printk(ip, fmt, ##args); \ 571 __trace_printk(ip, fmt, ##args); \
572} while (0) 572} while (0)
573 573
574/**
575 * tracepoint_string - register constant persistent string to trace system
576 * @str - a constant persistent string that will be referenced in tracepoints
577 *
578 * If constant strings are being used in tracepoints, it is faster and
579 * more efficient to just save the pointer to the string and reference
580 * that with a printf "%s" instead of saving the string in the ring buffer
581 * and wasting space and time.
582 *
583 * The problem with the above approach is that userspace tools that read
584 * the binary output of the trace buffers do not have access to the string.
585 * Instead they just show the address of the string which is not very
586 * useful to users.
587 *
588 * With tracepoint_string(), the string will be registered to the tracing
589 * system and exported to userspace via the debugfs/tracing/printk_formats
590 * file that maps the string address to the string text. This way userspace
591 * tools that read the binary buffers have a way to map the pointers to
592 * the ASCII strings they represent.
593 *
594 * The @str used must be a constant string and persistent as it would not
595 * make sense to show a string that no longer exists. But it is still fine
596 * to be used with modules, because when modules are unloaded, if they
597 * had tracepoints, the ring buffers are cleared too. As long as the string
598 * does not change during the life of the module, it is fine to use
599 * tracepoint_string() within a module.
600 */
601#define tracepoint_string(str) \
602 ({ \
603 static const char *___tp_str __tracepoint_string = str; \
604 ___tp_str; \
605 })
606#define __tracepoint_string __attribute__((section("__tracepoint_str")))
607
608#ifdef CONFIG_PERF_EVENTS 574#ifdef CONFIG_PERF_EVENTS
609struct perf_event; 575struct perf_event;
610 576
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 2e2a5f7717e5..b1293f15f592 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -249,6 +249,50 @@ extern void syscall_unregfunc(void);
249 249
250#endif /* CONFIG_TRACEPOINTS */ 250#endif /* CONFIG_TRACEPOINTS */
251 251
252#ifdef CONFIG_TRACING
253/**
254 * tracepoint_string - register constant persistent string to trace system
255 * @str - a constant persistent string that will be referenced in tracepoints
256 *
257 * If constant strings are being used in tracepoints, it is faster and
258 * more efficient to just save the pointer to the string and reference
259 * that with a printf "%s" instead of saving the string in the ring buffer
260 * and wasting space and time.
261 *
262 * The problem with the above approach is that userspace tools that read
263 * the binary output of the trace buffers do not have access to the string.
264 * Instead they just show the address of the string which is not very
265 * useful to users.
266 *
267 * With tracepoint_string(), the string will be registered to the tracing
268 * system and exported to userspace via the debugfs/tracing/printk_formats
269 * file that maps the string address to the string text. This way userspace
270 * tools that read the binary buffers have a way to map the pointers to
271 * the ASCII strings they represent.
272 *
273 * The @str used must be a constant string and persistent as it would not
274 * make sense to show a string that no longer exists. But it is still fine
275 * to be used with modules, because when modules are unloaded, if they
276 * had tracepoints, the ring buffers are cleared too. As long as the string
277 * does not change during the life of the module, it is fine to use
278 * tracepoint_string() within a module.
279 */
280#define tracepoint_string(str) \
281 ({ \
282 static const char *___tp_str __tracepoint_string = str; \
283 ___tp_str; \
284 })
285#define __tracepoint_string __attribute__((section("__tracepoint_str")))
286#else
287/*
288 * tracepoint_string() is used to save the string address for userspace
289 * tracing tools. When tracing isn't configured, there's no need to save
290 * anything.
291 */
292# define tracepoint_string(str) str
293# define __tracepoint_string
294#endif
295
252/* 296/*
253 * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype 297 * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype
254 * (void). "void" is a special value in a function prototype and can 298 * (void). "void" is a special value in a function prototype and can
diff --git a/include/trace/events/ipi.h b/include/trace/events/ipi.h
new file mode 100644
index 000000000000..834a7362a610
--- /dev/null
+++ b/include/trace/events/ipi.h
@@ -0,0 +1,89 @@
1#undef TRACE_SYSTEM
2#define TRACE_SYSTEM ipi
3
4#if !defined(_TRACE_IPI_H) || defined(TRACE_HEADER_MULTI_READ)
5#define _TRACE_IPI_H
6
7#include <linux/tracepoint.h>
8
9/**
10 * ipi_raise - called when a smp cross call is made
11 *
12 * @mask: mask of recipient CPUs for the IPI
13 * @reason: string identifying the IPI purpose
14 *
15 * It is necessary for @reason to be a static string declared with
16 * __tracepoint_string.
17 */
18TRACE_EVENT(ipi_raise,
19
20 TP_PROTO(const struct cpumask *mask, const char *reason),
21
22 TP_ARGS(mask, reason),
23
24 TP_STRUCT__entry(
25 __bitmask(target_cpus, nr_cpumask_bits)
26 __field(const char *, reason)
27 ),
28
29 TP_fast_assign(
30 __assign_bitmask(target_cpus, cpumask_bits(mask), nr_cpumask_bits);
31 __entry->reason = reason;
32 ),
33
34 TP_printk("target_mask=%s (%s)", __get_bitmask(target_cpus), __entry->reason)
35);
36
37DECLARE_EVENT_CLASS(ipi_handler,
38
39 TP_PROTO(const char *reason),
40
41 TP_ARGS(reason),
42
43 TP_STRUCT__entry(
44 __field(const char *, reason)
45 ),
46
47 TP_fast_assign(
48 __entry->reason = reason;
49 ),
50
51 TP_printk("(%s)", __entry->reason)
52);
53
54/**
55 * ipi_entry - called immediately before the IPI handler
56 *
57 * @reason: string identifying the IPI purpose
58 *
59 * It is necessary for @reason to be a static string declared with
60 * __tracepoint_string, ideally the same as used with trace_ipi_raise
61 * for that IPI.
62 */
63DEFINE_EVENT(ipi_handler, ipi_entry,
64
65 TP_PROTO(const char *reason),
66
67 TP_ARGS(reason)
68);
69
70/**
71 * ipi_exit - called immediately after the IPI handler returns
72 *
73 * @reason: string identifying the IPI purpose
74 *
75 * It is necessary for @reason to be a static string declared with
76 * __tracepoint_string, ideally the same as used with trace_ipi_raise for
77 * that IPI.
78 */
79DEFINE_EVENT(ipi_handler, ipi_exit,
80
81 TP_PROTO(const char *reason),
82
83 TP_ARGS(reason)
84);
85
86#endif /* _TRACE_IPI_H */
87
88/* This part must be outside protection */
89#include <trace/define_trace.h>