diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-03-13 06:54:40 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-13 06:57:22 -0400 |
commit | e9a22d1fb94050b7d600019c32e6b672d539054b (patch) | |
tree | 1e062f00e3fe7a3ace7b0c6b930ed6cdacd37166 /arch/x86/kernel/ds.c | |
parent | 321bb5e1ac461c04b6a93f795010d6eb01d8c5ca (diff) |
x86, bts: cleanups
Impact: cleanup, no code changed
Cc: Markus Metzger <markus.t.metzger@intel.com>
LKML-Reference: <20090313104218.A30096@sedona.ch.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r-- | arch/x86/kernel/ds.c | 142 |
1 files changed, 80 insertions, 62 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index d9cab716805..7363e01ba08 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -19,43 +19,52 @@ | |||
19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 | 19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 |
20 | */ | 20 | */ |
21 | 21 | ||
22 | 22 | #include <linux/kernel.h> | |
23 | #include <asm/ds.h> | ||
24 | |||
25 | #include <linux/errno.h> | ||
26 | #include <linux/string.h> | 23 | #include <linux/string.h> |
27 | #include <linux/slab.h> | 24 | #include <linux/errno.h> |
28 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
26 | #include <linux/slab.h> | ||
29 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
30 | #include <linux/kernel.h> | 28 | |
29 | #include <asm/ds.h> | ||
31 | 30 | ||
32 | #include "ds_selftest.h" | 31 | #include "ds_selftest.h" |
33 | 32 | ||
34 | /* | 33 | /* |
35 | * The configuration for a particular DS hardware implementation. | 34 | * The configuration for a particular DS hardware implementation: |
36 | */ | 35 | */ |
37 | struct ds_configuration { | 36 | struct ds_configuration { |
38 | /* The name of the configuration. */ | 37 | /* The name of the configuration: */ |
39 | const char *name; | 38 | const char *name; |
40 | /* The size of pointer-typed fields in DS, BTS, and PEBS. */ | 39 | |
41 | unsigned char sizeof_ptr_field; | 40 | /* The size of pointer-typed fields in DS, BTS, and PEBS: */ |
42 | /* The size of a BTS/PEBS record in bytes. */ | 41 | unsigned char sizeof_ptr_field; |
43 | unsigned char sizeof_rec[2]; | 42 | |
44 | /* Control bit-masks indexed by enum ds_feature. */ | 43 | /* The size of a BTS/PEBS record in bytes: */ |
45 | unsigned long ctl[dsf_ctl_max]; | 44 | unsigned char sizeof_rec[2]; |
45 | |||
46 | /* Control bit-masks indexed by enum ds_feature: */ | ||
47 | unsigned long ctl[dsf_ctl_max]; | ||
46 | }; | 48 | }; |
47 | static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); | 49 | static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); |
48 | 50 | ||
49 | #define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) | 51 | #define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) |
50 | 52 | ||
51 | #define MAX_SIZEOF_DS (12 * 8) /* Maximal size of a DS configuration. */ | 53 | /* Maximal size of a DS configuration: */ |
52 | #define MAX_SIZEOF_BTS (3 * 8) /* Maximal size of a BTS record. */ | 54 | #define MAX_SIZEOF_DS (12 * 8) |
53 | #define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment. */ | ||
54 | 55 | ||
55 | #define BTS_CONTROL \ | 56 | /* Maximal size of a BTS record: */ |
56 | (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\ | 57 | #define MAX_SIZEOF_BTS (3 * 8) |
57 | ds_cfg.ctl[dsf_bts_overflow]) | ||
58 | 58 | ||
59 | /* BTS and PEBS buffer alignment: */ | ||
60 | #define DS_ALIGNMENT (1 << 3) | ||
61 | |||
62 | /* Mask of control bits in the DS MSR register: */ | ||
63 | #define BTS_CONTROL \ | ||
64 | ( ds_cfg.ctl[dsf_bts] | \ | ||
65 | ds_cfg.ctl[dsf_bts_kernel] | \ | ||
66 | ds_cfg.ctl[dsf_bts_user] | \ | ||
67 | ds_cfg.ctl[dsf_bts_overflow] ) | ||
59 | 68 | ||
60 | /* | 69 | /* |
61 | * A BTS or PEBS tracer. | 70 | * A BTS or PEBS tracer. |
@@ -65,28 +74,32 @@ static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); | |||
65 | */ | 74 | */ |
66 | struct ds_tracer { | 75 | struct ds_tracer { |
67 | /* The DS context (partially) owned by this tracer. */ | 76 | /* The DS context (partially) owned by this tracer. */ |
68 | struct ds_context *context; | 77 | struct ds_context *context; |
69 | /* The buffer provided on ds_request() and its size in bytes. */ | 78 | /* The buffer provided on ds_request() and its size in bytes. */ |
70 | void *buffer; | 79 | void *buffer; |
71 | size_t size; | 80 | size_t size; |
72 | }; | 81 | }; |
73 | 82 | ||
74 | struct bts_tracer { | 83 | struct bts_tracer { |
75 | /* The common DS part. */ | 84 | /* The common DS part: */ |
76 | struct ds_tracer ds; | 85 | struct ds_tracer ds; |
77 | /* The trace including the DS configuration. */ | 86 | |
78 | struct bts_trace trace; | 87 | /* The trace including the DS configuration: */ |
79 | /* Buffer overflow notification function. */ | 88 | struct bts_trace trace; |
80 | bts_ovfl_callback_t ovfl; | 89 | |
90 | /* Buffer overflow notification function: */ | ||
91 | bts_ovfl_callback_t ovfl; | ||
81 | }; | 92 | }; |
82 | 93 | ||
83 | struct pebs_tracer { | 94 | struct pebs_tracer { |
84 | /* The common DS part. */ | 95 | /* The common DS part: */ |
85 | struct ds_tracer ds; | 96 | struct ds_tracer ds; |
86 | /* The trace including the DS configuration. */ | 97 | |
87 | struct pebs_trace trace; | 98 | /* The trace including the DS configuration: */ |
88 | /* Buffer overflow notification function. */ | 99 | struct pebs_trace trace; |
89 | pebs_ovfl_callback_t ovfl; | 100 | |
101 | /* Buffer overflow notification function: */ | ||
102 | pebs_ovfl_callback_t ovfl; | ||
90 | }; | 103 | }; |
91 | 104 | ||
92 | /* | 105 | /* |
@@ -95,6 +108,7 @@ struct pebs_tracer { | |||
95 | * | 108 | * |
96 | * The DS configuration consists of the following fields; different | 109 | * The DS configuration consists of the following fields; different |
97 | * architetures vary in the size of those fields. | 110 | * architetures vary in the size of those fields. |
111 | * | ||
98 | * - double-word aligned base linear address of the BTS buffer | 112 | * - double-word aligned base linear address of the BTS buffer |
99 | * - write pointer into the BTS buffer | 113 | * - write pointer into the BTS buffer |
100 | * - end linear address of the BTS buffer (one byte beyond the end of | 114 | * - end linear address of the BTS buffer (one byte beyond the end of |
@@ -133,19 +147,20 @@ enum ds_field { | |||
133 | }; | 147 | }; |
134 | 148 | ||
135 | enum ds_qualifier { | 149 | enum ds_qualifier { |
136 | ds_bts = 0, | 150 | ds_bts = 0, |
137 | ds_pebs | 151 | ds_pebs |
138 | }; | 152 | }; |
139 | 153 | ||
140 | static inline unsigned long ds_get(const unsigned char *base, | 154 | static inline unsigned long |
141 | enum ds_qualifier qual, enum ds_field field) | 155 | ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) |
142 | { | 156 | { |
143 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); | 157 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); |
144 | return *(unsigned long *)base; | 158 | return *(unsigned long *)base; |
145 | } | 159 | } |
146 | 160 | ||
147 | static inline void ds_set(unsigned char *base, enum ds_qualifier qual, | 161 | static inline void |
148 | enum ds_field field, unsigned long value) | 162 | ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, |
163 | unsigned long value) | ||
149 | { | 164 | { |
150 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); | 165 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); |
151 | (*(unsigned long *)base) = value; | 166 | (*(unsigned long *)base) = value; |
@@ -157,7 +172,6 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, | |||
157 | */ | 172 | */ |
158 | static DEFINE_SPINLOCK(ds_lock); | 173 | static DEFINE_SPINLOCK(ds_lock); |
159 | 174 | ||
160 | |||
161 | /* | 175 | /* |
162 | * We either support (system-wide) per-cpu or per-thread allocation. | 176 | * We either support (system-wide) per-cpu or per-thread allocation. |
163 | * We distinguish the two based on the task_struct pointer, where a | 177 | * We distinguish the two based on the task_struct pointer, where a |
@@ -211,17 +225,21 @@ static inline int check_tracer(struct task_struct *task) | |||
211 | * deallocated when the last user puts the context. | 225 | * deallocated when the last user puts the context. |
212 | */ | 226 | */ |
213 | struct ds_context { | 227 | struct ds_context { |
214 | /* The DS configuration; goes into MSR_IA32_DS_AREA. */ | 228 | /* The DS configuration; goes into MSR_IA32_DS_AREA: */ |
215 | unsigned char ds[MAX_SIZEOF_DS]; | 229 | unsigned char ds[MAX_SIZEOF_DS]; |
216 | /* The owner of the BTS and PEBS configuration, respectively. */ | 230 | |
217 | struct bts_tracer *bts_master; | 231 | /* The owner of the BTS and PEBS configuration, respectively: */ |
218 | struct pebs_tracer *pebs_master; | 232 | struct bts_tracer *bts_master; |
219 | /* Use count. */ | 233 | struct pebs_tracer *pebs_master; |
234 | |||
235 | /* Use count: */ | ||
220 | unsigned long count; | 236 | unsigned long count; |
221 | /* Pointer to the context pointer field. */ | 237 | |
222 | struct ds_context **this; | 238 | /* Pointer to the context pointer field: */ |
223 | /* The traced task; NULL for current cpu. */ | 239 | struct ds_context **this; |
224 | struct task_struct *task; | 240 | |
241 | /* The traced task; NULL for current cpu: */ | ||
242 | struct task_struct *task; | ||
225 | }; | 243 | }; |
226 | 244 | ||
227 | static DEFINE_PER_CPU(struct ds_context *, system_context_array); | 245 | static DEFINE_PER_CPU(struct ds_context *, system_context_array); |
@@ -328,9 +346,9 @@ static void ds_overflow(struct ds_context *context, enum ds_qualifier qual) | |||
328 | * The remainder of any partially written record is zeroed out. | 346 | * The remainder of any partially written record is zeroed out. |
329 | * | 347 | * |
330 | * context: the DS context | 348 | * context: the DS context |
331 | * qual: the buffer type | 349 | * qual: the buffer type |
332 | * record: the data to write | 350 | * record: the data to write |
333 | * size: the size of the data | 351 | * size: the size of the data |
334 | */ | 352 | */ |
335 | static int ds_write(struct ds_context *context, enum ds_qualifier qual, | 353 | static int ds_write(struct ds_context *context, enum ds_qualifier qual, |
336 | const void *record, size_t size) | 354 | const void *record, size_t size) |
@@ -429,12 +447,12 @@ enum bts_field { | |||
429 | bts_to, | 447 | bts_to, |
430 | bts_flags, | 448 | bts_flags, |
431 | 449 | ||
432 | bts_qual = bts_from, | 450 | bts_qual = bts_from, |
433 | bts_jiffies = bts_to, | 451 | bts_jiffies = bts_to, |
434 | bts_pid = bts_flags, | 452 | bts_pid = bts_flags, |
435 | 453 | ||
436 | bts_qual_mask = (bts_qual_max - 1), | 454 | bts_qual_mask = (bts_qual_max - 1), |
437 | bts_escape = ((unsigned long)-1 & ~bts_qual_mask) | 455 | bts_escape = ((unsigned long)-1 & ~bts_qual_mask) |
438 | }; | 456 | }; |
439 | 457 | ||
440 | static inline unsigned long bts_get(const char *base, enum bts_field field) | 458 | static inline unsigned long bts_get(const char *base, enum bts_field field) |
@@ -461,8 +479,8 @@ static inline void bts_set(char *base, enum bts_field field, unsigned long val) | |||
461 | * | 479 | * |
462 | * return: bytes read/written on success; -Eerrno, otherwise | 480 | * return: bytes read/written on success; -Eerrno, otherwise |
463 | */ | 481 | */ |
464 | static int bts_read(struct bts_tracer *tracer, const void *at, | 482 | static int |
465 | struct bts_struct *out) | 483 | bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) |
466 | { | 484 | { |
467 | if (!tracer) | 485 | if (!tracer) |
468 | return -EINVAL; | 486 | return -EINVAL; |