diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/irq_work.h | 20 | ||||
-rw-r--r-- | include/linux/jump_label.h | 18 | ||||
-rw-r--r-- | include/linux/jump_label_ref.h | 44 | ||||
-rw-r--r-- | include/linux/perf_event.h | 57 |
4 files changed, 115 insertions, 24 deletions
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h new file mode 100644 index 000000000000..4fa09d4d0b71 --- /dev/null +++ b/include/linux/irq_work.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef _LINUX_IRQ_WORK_H | ||
2 | #define _LINUX_IRQ_WORK_H | ||
3 | |||
4 | struct irq_work { | ||
5 | struct irq_work *next; | ||
6 | void (*func)(struct irq_work *); | ||
7 | }; | ||
8 | |||
9 | static inline | ||
10 | void init_irq_work(struct irq_work *entry, void (*func)(struct irq_work *)) | ||
11 | { | ||
12 | entry->next = NULL; | ||
13 | entry->func = func; | ||
14 | } | ||
15 | |||
16 | bool irq_work_queue(struct irq_work *entry); | ||
17 | void irq_work_run(void); | ||
18 | void irq_work_sync(struct irq_work *entry); | ||
19 | |||
20 | #endif /* _LINUX_IRQ_WORK_H */ | ||
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index b72cd9f92c2e..b67cb180e6e9 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -25,10 +25,10 @@ extern void jump_label_update(unsigned long key, enum jump_label_type type); | |||
25 | extern void jump_label_apply_nops(struct module *mod); | 25 | extern void jump_label_apply_nops(struct module *mod); |
26 | extern int jump_label_text_reserved(void *start, void *end); | 26 | extern int jump_label_text_reserved(void *start, void *end); |
27 | 27 | ||
28 | #define enable_jump_label(key) \ | 28 | #define jump_label_enable(key) \ |
29 | jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE); | 29 | jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE); |
30 | 30 | ||
31 | #define disable_jump_label(key) \ | 31 | #define jump_label_disable(key) \ |
32 | jump_label_update((unsigned long)key, JUMP_LABEL_DISABLE); | 32 | jump_label_update((unsigned long)key, JUMP_LABEL_DISABLE); |
33 | 33 | ||
34 | #else | 34 | #else |
@@ -39,12 +39,12 @@ do { \ | |||
39 | goto label; \ | 39 | goto label; \ |
40 | } while (0) | 40 | } while (0) |
41 | 41 | ||
42 | #define enable_jump_label(cond_var) \ | 42 | #define jump_label_enable(cond_var) \ |
43 | do { \ | 43 | do { \ |
44 | *(cond_var) = 1; \ | 44 | *(cond_var) = 1; \ |
45 | } while (0) | 45 | } while (0) |
46 | 46 | ||
47 | #define disable_jump_label(cond_var) \ | 47 | #define jump_label_disable(cond_var) \ |
48 | do { \ | 48 | do { \ |
49 | *(cond_var) = 0; \ | 49 | *(cond_var) = 0; \ |
50 | } while (0) | 50 | } while (0) |
@@ -61,4 +61,14 @@ static inline int jump_label_text_reserved(void *start, void *end) | |||
61 | 61 | ||
62 | #endif | 62 | #endif |
63 | 63 | ||
64 | #define COND_STMT(key, stmt) \ | ||
65 | do { \ | ||
66 | __label__ jl_enabled; \ | ||
67 | JUMP_LABEL(key, jl_enabled); \ | ||
68 | if (0) { \ | ||
69 | jl_enabled: \ | ||
70 | stmt; \ | ||
71 | } \ | ||
72 | } while (0) | ||
73 | |||
64 | #endif | 74 | #endif |
diff --git a/include/linux/jump_label_ref.h b/include/linux/jump_label_ref.h new file mode 100644 index 000000000000..e5d012ad92c6 --- /dev/null +++ b/include/linux/jump_label_ref.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef _LINUX_JUMP_LABEL_REF_H | ||
2 | #define _LINUX_JUMP_LABEL_REF_H | ||
3 | |||
4 | #include <linux/jump_label.h> | ||
5 | #include <asm/atomic.h> | ||
6 | |||
7 | #ifdef HAVE_JUMP_LABEL | ||
8 | |||
9 | static inline void jump_label_inc(atomic_t *key) | ||
10 | { | ||
11 | if (atomic_add_return(1, key) == 1) | ||
12 | jump_label_enable(key); | ||
13 | } | ||
14 | |||
15 | static inline void jump_label_dec(atomic_t *key) | ||
16 | { | ||
17 | if (atomic_dec_and_test(key)) | ||
18 | jump_label_disable(key); | ||
19 | } | ||
20 | |||
21 | #else /* !HAVE_JUMP_LABEL */ | ||
22 | |||
23 | static inline void jump_label_inc(atomic_t *key) | ||
24 | { | ||
25 | atomic_inc(key); | ||
26 | } | ||
27 | |||
28 | static inline void jump_label_dec(atomic_t *key) | ||
29 | { | ||
30 | atomic_dec(key); | ||
31 | } | ||
32 | |||
33 | #undef JUMP_LABEL | ||
34 | #define JUMP_LABEL(key, label) \ | ||
35 | do { \ | ||
36 | if (unlikely(__builtin_choose_expr( \ | ||
37 | __builtin_types_compatible_p(typeof(key), atomic_t *), \ | ||
38 | atomic_read((atomic_t *)(key)), *(key)))) \ | ||
39 | goto label; \ | ||
40 | } while (0) | ||
41 | |||
42 | #endif /* HAVE_JUMP_LABEL */ | ||
43 | |||
44 | #endif /* _LINUX_JUMP_LABEL_REF_H */ | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index a9227e985207..057bf22a8323 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -486,6 +486,8 @@ struct perf_guest_info_callbacks { | |||
486 | #include <linux/workqueue.h> | 486 | #include <linux/workqueue.h> |
487 | #include <linux/ftrace.h> | 487 | #include <linux/ftrace.h> |
488 | #include <linux/cpu.h> | 488 | #include <linux/cpu.h> |
489 | #include <linux/irq_work.h> | ||
490 | #include <linux/jump_label_ref.h> | ||
489 | #include <asm/atomic.h> | 491 | #include <asm/atomic.h> |
490 | #include <asm/local.h> | 492 | #include <asm/local.h> |
491 | 493 | ||
@@ -535,6 +537,12 @@ struct hw_perf_event { | |||
535 | struct { /* breakpoint */ | 537 | struct { /* breakpoint */ |
536 | struct arch_hw_breakpoint info; | 538 | struct arch_hw_breakpoint info; |
537 | struct list_head bp_list; | 539 | struct list_head bp_list; |
540 | /* | ||
541 | * Crufty hack to avoid the chicken and egg | ||
542 | * problem hw_breakpoint has with context | ||
543 | * creation and event initalization. | ||
544 | */ | ||
545 | struct task_struct *bp_target; | ||
538 | }; | 546 | }; |
539 | #endif | 547 | #endif |
540 | }; | 548 | }; |
@@ -672,11 +680,6 @@ struct perf_buffer { | |||
672 | void *data_pages[0]; | 680 | void *data_pages[0]; |
673 | }; | 681 | }; |
674 | 682 | ||
675 | struct perf_pending_entry { | ||
676 | struct perf_pending_entry *next; | ||
677 | void (*func)(struct perf_pending_entry *); | ||
678 | }; | ||
679 | |||
680 | struct perf_sample_data; | 683 | struct perf_sample_data; |
681 | 684 | ||
682 | typedef void (*perf_overflow_handler_t)(struct perf_event *, int, | 685 | typedef void (*perf_overflow_handler_t)(struct perf_event *, int, |
@@ -697,6 +700,7 @@ struct swevent_hlist { | |||
697 | 700 | ||
698 | #define PERF_ATTACH_CONTEXT 0x01 | 701 | #define PERF_ATTACH_CONTEXT 0x01 |
699 | #define PERF_ATTACH_GROUP 0x02 | 702 | #define PERF_ATTACH_GROUP 0x02 |
703 | #define PERF_ATTACH_TASK 0x04 | ||
700 | 704 | ||
701 | /** | 705 | /** |
702 | * struct perf_event - performance event kernel representation: | 706 | * struct perf_event - performance event kernel representation: |
@@ -784,7 +788,7 @@ struct perf_event { | |||
784 | int pending_wakeup; | 788 | int pending_wakeup; |
785 | int pending_kill; | 789 | int pending_kill; |
786 | int pending_disable; | 790 | int pending_disable; |
787 | struct perf_pending_entry pending; | 791 | struct irq_work pending; |
788 | 792 | ||
789 | atomic_t event_limit; | 793 | atomic_t event_limit; |
790 | 794 | ||
@@ -892,14 +896,26 @@ extern void perf_pmu_unregister(struct pmu *pmu); | |||
892 | 896 | ||
893 | extern int perf_num_counters(void); | 897 | extern int perf_num_counters(void); |
894 | extern const char *perf_pmu_name(void); | 898 | extern const char *perf_pmu_name(void); |
895 | extern void perf_event_task_sched_in(struct task_struct *task); | 899 | extern void __perf_event_task_sched_in(struct task_struct *task); |
896 | extern void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next); | 900 | extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next); |
901 | |||
902 | extern atomic_t perf_task_events; | ||
903 | |||
904 | static inline void perf_event_task_sched_in(struct task_struct *task) | ||
905 | { | ||
906 | COND_STMT(&perf_task_events, __perf_event_task_sched_in(task)); | ||
907 | } | ||
908 | |||
909 | static inline | ||
910 | void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) | ||
911 | { | ||
912 | COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next)); | ||
913 | } | ||
914 | |||
897 | extern int perf_event_init_task(struct task_struct *child); | 915 | extern int perf_event_init_task(struct task_struct *child); |
898 | extern void perf_event_exit_task(struct task_struct *child); | 916 | extern void perf_event_exit_task(struct task_struct *child); |
899 | extern void perf_event_free_task(struct task_struct *task); | 917 | extern void perf_event_free_task(struct task_struct *task); |
900 | extern void perf_event_delayed_put(struct task_struct *task); | 918 | extern void perf_event_delayed_put(struct task_struct *task); |
901 | extern void set_perf_event_pending(void); | ||
902 | extern void perf_event_do_pending(void); | ||
903 | extern void perf_event_print_debug(void); | 919 | extern void perf_event_print_debug(void); |
904 | extern void perf_pmu_disable(struct pmu *pmu); | 920 | extern void perf_pmu_disable(struct pmu *pmu); |
905 | extern void perf_pmu_enable(struct pmu *pmu); | 921 | extern void perf_pmu_enable(struct pmu *pmu); |
@@ -988,18 +1004,20 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs) | |||
988 | perf_arch_fetch_caller_regs(regs, CALLER_ADDR0); | 1004 | perf_arch_fetch_caller_regs(regs, CALLER_ADDR0); |
989 | } | 1005 | } |
990 | 1006 | ||
991 | static inline void | 1007 | static __always_inline void |
992 | perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) | 1008 | perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) |
993 | { | 1009 | { |
994 | if (atomic_read(&perf_swevent_enabled[event_id])) { | 1010 | struct pt_regs hot_regs; |
995 | struct pt_regs hot_regs; | 1011 | |
996 | 1012 | JUMP_LABEL(&perf_swevent_enabled[event_id], have_event); | |
997 | if (!regs) { | 1013 | return; |
998 | perf_fetch_caller_regs(&hot_regs); | 1014 | |
999 | regs = &hot_regs; | 1015 | have_event: |
1000 | } | 1016 | if (!regs) { |
1001 | __perf_sw_event(event_id, nr, nmi, regs, addr); | 1017 | perf_fetch_caller_regs(&hot_regs); |
1018 | regs = &hot_regs; | ||
1002 | } | 1019 | } |
1020 | __perf_sw_event(event_id, nr, nmi, regs, addr); | ||
1003 | } | 1021 | } |
1004 | 1022 | ||
1005 | extern void perf_event_mmap(struct vm_area_struct *vma); | 1023 | extern void perf_event_mmap(struct vm_area_struct *vma); |
@@ -1078,7 +1096,6 @@ static inline int perf_event_init_task(struct task_struct *child) { return 0; } | |||
1078 | static inline void perf_event_exit_task(struct task_struct *child) { } | 1096 | static inline void perf_event_exit_task(struct task_struct *child) { } |
1079 | static inline void perf_event_free_task(struct task_struct *task) { } | 1097 | static inline void perf_event_free_task(struct task_struct *task) { } |
1080 | static inline void perf_event_delayed_put(struct task_struct *task) { } | 1098 | static inline void perf_event_delayed_put(struct task_struct *task) { } |
1081 | static inline void perf_event_do_pending(void) { } | ||
1082 | static inline void perf_event_print_debug(void) { } | 1099 | static inline void perf_event_print_debug(void) { } |
1083 | static inline int perf_event_task_disable(void) { return -EINVAL; } | 1100 | static inline int perf_event_task_disable(void) { return -EINVAL; } |
1084 | static inline int perf_event_task_enable(void) { return -EINVAL; } | 1101 | static inline int perf_event_task_enable(void) { return -EINVAL; } |