diff options
-rw-r--r-- | arch/x86/kernel/ds.c | 58 |
1 files changed, 37 insertions, 21 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index b1d6e1f502fa..c730155bf54d 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -89,6 +89,9 @@ struct bts_tracer { | |||
89 | 89 | ||
90 | /* Buffer overflow notification function: */ | 90 | /* Buffer overflow notification function: */ |
91 | bts_ovfl_callback_t ovfl; | 91 | bts_ovfl_callback_t ovfl; |
92 | |||
93 | /* Active flags affecting trace collection. */ | ||
94 | unsigned int flags; | ||
92 | }; | 95 | }; |
93 | 96 | ||
94 | struct pebs_tracer { | 97 | struct pebs_tracer { |
@@ -799,6 +802,8 @@ void ds_suspend_bts(struct bts_tracer *tracer) | |||
799 | if (!tracer) | 802 | if (!tracer) |
800 | return; | 803 | return; |
801 | 804 | ||
805 | tracer->flags = 0; | ||
806 | |||
802 | task = tracer->ds.context->task; | 807 | task = tracer->ds.context->task; |
803 | 808 | ||
804 | if (!task || (task == current)) | 809 | if (!task || (task == current)) |
@@ -820,6 +825,8 @@ void ds_resume_bts(struct bts_tracer *tracer) | |||
820 | if (!tracer) | 825 | if (!tracer) |
821 | return; | 826 | return; |
822 | 827 | ||
828 | tracer->flags = tracer->trace.ds.flags; | ||
829 | |||
823 | task = tracer->ds.context->task; | 830 | task = tracer->ds.context->task; |
824 | 831 | ||
825 | control = ds_cfg.ctl[dsf_bts]; | 832 | control = ds_cfg.ctl[dsf_bts]; |
@@ -1037,43 +1044,52 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) | |||
1037 | } | 1044 | } |
1038 | } | 1045 | } |
1039 | 1046 | ||
1047 | static inline void ds_take_timestamp(struct ds_context *context, | ||
1048 | enum bts_qualifier qualifier, | ||
1049 | struct task_struct *task) | ||
1050 | { | ||
1051 | struct bts_tracer *tracer = context->bts_master; | ||
1052 | struct bts_struct ts; | ||
1053 | |||
1054 | /* Prevent compilers from reading the tracer pointer twice. */ | ||
1055 | barrier(); | ||
1056 | |||
1057 | if (!tracer || !(tracer->flags & BTS_TIMESTAMPS)) | ||
1058 | return; | ||
1059 | |||
1060 | memset(&ts, 0, sizeof(ts)); | ||
1061 | ts.qualifier = qualifier; | ||
1062 | ts.variant.timestamp.jiffies = jiffies_64; | ||
1063 | ts.variant.timestamp.pid = task->pid; | ||
1064 | |||
1065 | bts_write(tracer, &ts); | ||
1066 | } | ||
1067 | |||
1040 | /* | 1068 | /* |
1041 | * Change the DS configuration from tracing prev to tracing next. | 1069 | * Change the DS configuration from tracing prev to tracing next. |
1042 | */ | 1070 | */ |
1043 | void ds_switch_to(struct task_struct *prev, struct task_struct *next) | 1071 | void ds_switch_to(struct task_struct *prev, struct task_struct *next) |
1044 | { | 1072 | { |
1045 | struct ds_context *prev_ctx = prev->thread.ds_ctx; | 1073 | struct ds_context *prev_ctx = prev->thread.ds_ctx; |
1046 | struct ds_context *next_ctx = next->thread.ds_ctx; | 1074 | struct ds_context *next_ctx = next->thread.ds_ctx; |
1075 | unsigned long debugctlmsr = next->thread.debugctlmsr; | ||
1076 | |||
1077 | /* Make sure all data is read before we start. */ | ||
1078 | barrier(); | ||
1047 | 1079 | ||
1048 | if (prev_ctx) { | 1080 | if (prev_ctx) { |
1049 | update_debugctlmsr(0); | 1081 | update_debugctlmsr(0); |
1050 | 1082 | ||
1051 | if (prev_ctx->bts_master && | 1083 | ds_take_timestamp(prev_ctx, bts_task_departs, prev); |
1052 | (prev_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { | ||
1053 | struct bts_struct ts = { | ||
1054 | .qualifier = bts_task_departs, | ||
1055 | .variant.timestamp.jiffies = jiffies_64, | ||
1056 | .variant.timestamp.pid = prev->pid | ||
1057 | }; | ||
1058 | bts_write(prev_ctx->bts_master, &ts); | ||
1059 | } | ||
1060 | } | 1084 | } |
1061 | 1085 | ||
1062 | if (next_ctx) { | 1086 | if (next_ctx) { |
1063 | if (next_ctx->bts_master && | 1087 | ds_take_timestamp(next_ctx, bts_task_arrives, next); |
1064 | (next_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { | ||
1065 | struct bts_struct ts = { | ||
1066 | .qualifier = bts_task_arrives, | ||
1067 | .variant.timestamp.jiffies = jiffies_64, | ||
1068 | .variant.timestamp.pid = next->pid | ||
1069 | }; | ||
1070 | bts_write(next_ctx->bts_master, &ts); | ||
1071 | } | ||
1072 | 1088 | ||
1073 | wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds); | 1089 | wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds); |
1074 | } | 1090 | } |
1075 | 1091 | ||
1076 | update_debugctlmsr(next->thread.debugctlmsr); | 1092 | update_debugctlmsr(debugctlmsr); |
1077 | } | 1093 | } |
1078 | 1094 | ||
1079 | void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) | 1095 | void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) |