aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/ds.c58
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
94struct pebs_tracer { 97struct 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
1047static 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 */
1043void ds_switch_to(struct task_struct *prev, struct task_struct *next) 1071void 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
1079void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) 1095void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)