diff options
author | Robert Richter <robert.richter@amd.com> | 2009-01-08 08:27:34 -0500 |
---|---|---|
committer | Robert Richter <robert.richter@amd.com> | 2009-01-08 08:27:34 -0500 |
commit | d2852b932f0bb5e89177aa27c7bcf07f4167e129 (patch) | |
tree | 96d975ae155ba307acd07968939fff22afedddf7 /arch/x86 | |
parent | 4a6908a3a050aacc9c3a2f36b276b46c0629ad91 (diff) | |
parent | 14f0ca8eaea42a5b5a69cfcb699665dd2618db5f (diff) |
Merge branch 'oprofile/ring_buffer' into oprofile/oprofile-for-tip
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/oprofile/op_model_amd.c | 224 |
1 files changed, 91 insertions, 133 deletions
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 509513760a6e..8fdf06e4edf9 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * @file op_model_amd.c | 2 | * @file op_model_amd.c |
3 | * athlon / K7 / K8 / Family 10h model-specific MSR operations | 3 | * athlon / K7 / K8 / Family 10h model-specific MSR operations |
4 | * | 4 | * |
5 | * @remark Copyright 2002-2008 OProfile authors | 5 | * @remark Copyright 2002-2009 OProfile authors |
6 | * @remark Read the file COPYING | 6 | * @remark Read the file COPYING |
7 | * | 7 | * |
8 | * @author John Levon | 8 | * @author John Levon |
@@ -10,7 +10,7 @@ | |||
10 | * @author Graydon Hoare | 10 | * @author Graydon Hoare |
11 | * @author Robert Richter <robert.richter@amd.com> | 11 | * @author Robert Richter <robert.richter@amd.com> |
12 | * @author Barry Kasindorf | 12 | * @author Barry Kasindorf |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/oprofile.h> | 15 | #include <linux/oprofile.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
@@ -60,56 +60,10 @@ static unsigned long reset_value[NUM_COUNTERS]; | |||
60 | #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ | 60 | #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ |
61 | #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ | 61 | #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ |
62 | 62 | ||
63 | /* Codes used in cpu_buffer.c */ | 63 | #define IBS_FETCH_SIZE 6 |
64 | /* This produces duplicate code, need to be fixed */ | 64 | #define IBS_OP_SIZE 12 |
65 | #define IBS_FETCH_BEGIN 3 | ||
66 | #define IBS_OP_BEGIN 4 | ||
67 | |||
68 | /* The function interface needs to be fixed, something like add | ||
69 | data. Should then be added to linux/oprofile.h. */ | ||
70 | extern void | ||
71 | oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
72 | unsigned int *const ibs_sample, int ibs_code); | ||
73 | |||
74 | struct ibs_fetch_sample { | ||
75 | /* MSRC001_1031 IBS Fetch Linear Address Register */ | ||
76 | unsigned int ibs_fetch_lin_addr_low; | ||
77 | unsigned int ibs_fetch_lin_addr_high; | ||
78 | /* MSRC001_1030 IBS Fetch Control Register */ | ||
79 | unsigned int ibs_fetch_ctl_low; | ||
80 | unsigned int ibs_fetch_ctl_high; | ||
81 | /* MSRC001_1032 IBS Fetch Physical Address Register */ | ||
82 | unsigned int ibs_fetch_phys_addr_low; | ||
83 | unsigned int ibs_fetch_phys_addr_high; | ||
84 | }; | ||
85 | |||
86 | struct ibs_op_sample { | ||
87 | /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */ | ||
88 | unsigned int ibs_op_rip_low; | ||
89 | unsigned int ibs_op_rip_high; | ||
90 | /* MSRC001_1035 IBS Op Data Register */ | ||
91 | unsigned int ibs_op_data1_low; | ||
92 | unsigned int ibs_op_data1_high; | ||
93 | /* MSRC001_1036 IBS Op Data 2 Register */ | ||
94 | unsigned int ibs_op_data2_low; | ||
95 | unsigned int ibs_op_data2_high; | ||
96 | /* MSRC001_1037 IBS Op Data 3 Register */ | ||
97 | unsigned int ibs_op_data3_low; | ||
98 | unsigned int ibs_op_data3_high; | ||
99 | /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */ | ||
100 | unsigned int ibs_dc_linear_low; | ||
101 | unsigned int ibs_dc_linear_high; | ||
102 | /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */ | ||
103 | unsigned int ibs_dc_phys_low; | ||
104 | unsigned int ibs_dc_phys_high; | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+ | ||
109 | */ | ||
110 | static void clear_ibs_nmi(void); | ||
111 | 65 | ||
112 | static int ibs_allowed; /* AMD Family10h and later */ | 66 | static int has_ibs; /* AMD Family10h and later */ |
113 | 67 | ||
114 | struct op_ibs_config { | 68 | struct op_ibs_config { |
115 | unsigned long op_enabled; | 69 | unsigned long op_enabled; |
@@ -200,31 +154,29 @@ static inline int | |||
200 | op_amd_handle_ibs(struct pt_regs * const regs, | 154 | op_amd_handle_ibs(struct pt_regs * const regs, |
201 | struct op_msrs const * const msrs) | 155 | struct op_msrs const * const msrs) |
202 | { | 156 | { |
203 | unsigned int low, high; | 157 | u32 low, high; |
204 | struct ibs_fetch_sample ibs_fetch; | 158 | u64 msr; |
205 | struct ibs_op_sample ibs_op; | 159 | struct op_entry entry; |
206 | 160 | ||
207 | if (!ibs_allowed) | 161 | if (!has_ibs) |
208 | return 1; | 162 | return 1; |
209 | 163 | ||
210 | if (ibs_config.fetch_enabled) { | 164 | if (ibs_config.fetch_enabled) { |
211 | rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); | 165 | rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); |
212 | if (high & IBS_FETCH_HIGH_VALID_BIT) { | 166 | if (high & IBS_FETCH_HIGH_VALID_BIT) { |
213 | ibs_fetch.ibs_fetch_ctl_high = high; | 167 | rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); |
214 | ibs_fetch.ibs_fetch_ctl_low = low; | 168 | oprofile_write_reserve(&entry, regs, msr, |
215 | rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high); | 169 | IBS_FETCH_CODE, IBS_FETCH_SIZE); |
216 | ibs_fetch.ibs_fetch_lin_addr_high = high; | 170 | oprofile_add_data(&entry, (u32)msr); |
217 | ibs_fetch.ibs_fetch_lin_addr_low = low; | 171 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
218 | rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high); | 172 | oprofile_add_data(&entry, low); |
219 | ibs_fetch.ibs_fetch_phys_addr_high = high; | 173 | oprofile_add_data(&entry, high); |
220 | ibs_fetch.ibs_fetch_phys_addr_low = low; | 174 | rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); |
221 | 175 | oprofile_add_data(&entry, (u32)msr); | |
222 | oprofile_add_ibs_sample(regs, | 176 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
223 | (unsigned int *)&ibs_fetch, | 177 | oprofile_write_commit(&entry); |
224 | IBS_FETCH_BEGIN); | 178 | |
225 | 179 | /* reenable the IRQ */ | |
226 | /*reenable the IRQ */ | ||
227 | rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); | ||
228 | high &= ~IBS_FETCH_HIGH_VALID_BIT; | 180 | high &= ~IBS_FETCH_HIGH_VALID_BIT; |
229 | high |= IBS_FETCH_HIGH_ENABLE; | 181 | high |= IBS_FETCH_HIGH_ENABLE; |
230 | low &= IBS_FETCH_LOW_MAX_CNT_MASK; | 182 | low &= IBS_FETCH_LOW_MAX_CNT_MASK; |
@@ -235,30 +187,29 @@ op_amd_handle_ibs(struct pt_regs * const regs, | |||
235 | if (ibs_config.op_enabled) { | 187 | if (ibs_config.op_enabled) { |
236 | rdmsr(MSR_AMD64_IBSOPCTL, low, high); | 188 | rdmsr(MSR_AMD64_IBSOPCTL, low, high); |
237 | if (low & IBS_OP_LOW_VALID_BIT) { | 189 | if (low & IBS_OP_LOW_VALID_BIT) { |
238 | rdmsr(MSR_AMD64_IBSOPRIP, low, high); | 190 | rdmsrl(MSR_AMD64_IBSOPRIP, msr); |
239 | ibs_op.ibs_op_rip_low = low; | 191 | oprofile_write_reserve(&entry, regs, msr, |
240 | ibs_op.ibs_op_rip_high = high; | 192 | IBS_OP_CODE, IBS_OP_SIZE); |
241 | rdmsr(MSR_AMD64_IBSOPDATA, low, high); | 193 | oprofile_add_data(&entry, (u32)msr); |
242 | ibs_op.ibs_op_data1_low = low; | 194 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
243 | ibs_op.ibs_op_data1_high = high; | 195 | rdmsrl(MSR_AMD64_IBSOPDATA, msr); |
244 | rdmsr(MSR_AMD64_IBSOPDATA2, low, high); | 196 | oprofile_add_data(&entry, (u32)msr); |
245 | ibs_op.ibs_op_data2_low = low; | 197 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
246 | ibs_op.ibs_op_data2_high = high; | 198 | rdmsrl(MSR_AMD64_IBSOPDATA2, msr); |
247 | rdmsr(MSR_AMD64_IBSOPDATA3, low, high); | 199 | oprofile_add_data(&entry, (u32)msr); |
248 | ibs_op.ibs_op_data3_low = low; | 200 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
249 | ibs_op.ibs_op_data3_high = high; | 201 | rdmsrl(MSR_AMD64_IBSOPDATA3, msr); |
250 | rdmsr(MSR_AMD64_IBSDCLINAD, low, high); | 202 | oprofile_add_data(&entry, (u32)msr); |
251 | ibs_op.ibs_dc_linear_low = low; | 203 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
252 | ibs_op.ibs_dc_linear_high = high; | 204 | rdmsrl(MSR_AMD64_IBSDCLINAD, msr); |
253 | rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high); | 205 | oprofile_add_data(&entry, (u32)msr); |
254 | ibs_op.ibs_dc_phys_low = low; | 206 | oprofile_add_data(&entry, (u32)(msr >> 32)); |
255 | ibs_op.ibs_dc_phys_high = high; | 207 | rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); |
208 | oprofile_add_data(&entry, (u32)msr); | ||
209 | oprofile_add_data(&entry, (u32)(msr >> 32)); | ||
210 | oprofile_write_commit(&entry); | ||
256 | 211 | ||
257 | /* reenable the IRQ */ | 212 | /* reenable the IRQ */ |
258 | oprofile_add_ibs_sample(regs, | ||
259 | (unsigned int *)&ibs_op, | ||
260 | IBS_OP_BEGIN); | ||
261 | rdmsr(MSR_AMD64_IBSOPCTL, low, high); | ||
262 | high = 0; | 213 | high = 0; |
263 | low &= ~IBS_OP_LOW_VALID_BIT; | 214 | low &= ~IBS_OP_LOW_VALID_BIT; |
264 | low |= IBS_OP_LOW_ENABLE; | 215 | low |= IBS_OP_LOW_ENABLE; |
@@ -308,14 +259,14 @@ static void op_amd_start(struct op_msrs const * const msrs) | |||
308 | } | 259 | } |
309 | 260 | ||
310 | #ifdef CONFIG_OPROFILE_IBS | 261 | #ifdef CONFIG_OPROFILE_IBS |
311 | if (ibs_allowed && ibs_config.fetch_enabled) { | 262 | if (has_ibs && ibs_config.fetch_enabled) { |
312 | low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; | 263 | low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; |
313 | high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ | 264 | high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ |
314 | + IBS_FETCH_HIGH_ENABLE; | 265 | + IBS_FETCH_HIGH_ENABLE; |
315 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); | 266 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); |
316 | } | 267 | } |
317 | 268 | ||
318 | if (ibs_allowed && ibs_config.op_enabled) { | 269 | if (has_ibs && ibs_config.op_enabled) { |
319 | low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) | 270 | low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) |
320 | + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ | 271 | + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ |
321 | + IBS_OP_LOW_ENABLE; | 272 | + IBS_OP_LOW_ENABLE; |
@@ -331,8 +282,10 @@ static void op_amd_stop(struct op_msrs const * const msrs) | |||
331 | unsigned int low, high; | 282 | unsigned int low, high; |
332 | int i; | 283 | int i; |
333 | 284 | ||
334 | /* Subtle: stop on all counters to avoid race with | 285 | /* |
335 | * setting our pm callback */ | 286 | * Subtle: stop on all counters to avoid race with setting our |
287 | * pm callback | ||
288 | */ | ||
336 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | 289 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { |
337 | if (!reset_value[i]) | 290 | if (!reset_value[i]) |
338 | continue; | 291 | continue; |
@@ -342,14 +295,16 @@ static void op_amd_stop(struct op_msrs const * const msrs) | |||
342 | } | 295 | } |
343 | 296 | ||
344 | #ifdef CONFIG_OPROFILE_IBS | 297 | #ifdef CONFIG_OPROFILE_IBS |
345 | if (ibs_allowed && ibs_config.fetch_enabled) { | 298 | if (has_ibs && ibs_config.fetch_enabled) { |
346 | low = 0; /* clear max count and enable */ | 299 | /* clear max count and enable */ |
300 | low = 0; | ||
347 | high = 0; | 301 | high = 0; |
348 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); | 302 | wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); |
349 | } | 303 | } |
350 | 304 | ||
351 | if (ibs_allowed && ibs_config.op_enabled) { | 305 | if (has_ibs && ibs_config.op_enabled) { |
352 | low = 0; /* clear max count and enable */ | 306 | /* clear max count and enable */ |
307 | low = 0; | ||
353 | high = 0; | 308 | high = 0; |
354 | wrmsr(MSR_AMD64_IBSOPCTL, low, high); | 309 | wrmsr(MSR_AMD64_IBSOPCTL, low, high); |
355 | } | 310 | } |
@@ -370,18 +325,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) | |||
370 | } | 325 | } |
371 | } | 326 | } |
372 | 327 | ||
373 | #ifndef CONFIG_OPROFILE_IBS | 328 | #ifdef CONFIG_OPROFILE_IBS |
374 | |||
375 | /* no IBS support */ | ||
376 | |||
377 | static int op_amd_init(struct oprofile_operations *ops) | ||
378 | { | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static void op_amd_exit(void) {} | ||
383 | |||
384 | #else | ||
385 | 329 | ||
386 | static u8 ibs_eilvt_off; | 330 | static u8 ibs_eilvt_off; |
387 | 331 | ||
@@ -395,7 +339,7 @@ static inline void apic_clear_ibs_nmi_per_cpu(void *arg) | |||
395 | setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); | 339 | setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); |
396 | } | 340 | } |
397 | 341 | ||
398 | static int pfm_amd64_setup_eilvt(void) | 342 | static int init_ibs_nmi(void) |
399 | { | 343 | { |
400 | #define IBSCTL_LVTOFFSETVAL (1 << 8) | 344 | #define IBSCTL_LVTOFFSETVAL (1 << 8) |
401 | #define IBSCTL 0x1cc | 345 | #define IBSCTL 0x1cc |
@@ -419,6 +363,7 @@ static int pfm_amd64_setup_eilvt(void) | |||
419 | | IBSCTL_LVTOFFSETVAL); | 363 | | IBSCTL_LVTOFFSETVAL); |
420 | pci_read_config_dword(cpu_cfg, IBSCTL, &value); | 364 | pci_read_config_dword(cpu_cfg, IBSCTL, &value); |
421 | if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { | 365 | if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { |
366 | pci_dev_put(cpu_cfg); | ||
422 | printk(KERN_DEBUG "Failed to setup IBS LVT offset, " | 367 | printk(KERN_DEBUG "Failed to setup IBS LVT offset, " |
423 | "IBSCTL = 0x%08x", value); | 368 | "IBSCTL = 0x%08x", value); |
424 | return 1; | 369 | return 1; |
@@ -443,33 +388,35 @@ static int pfm_amd64_setup_eilvt(void) | |||
443 | return 0; | 388 | return 0; |
444 | } | 389 | } |
445 | 390 | ||
446 | /* | 391 | /* uninitialize the APIC for the IBS interrupts if needed */ |
447 | * initialize the APIC for the IBS interrupts | 392 | static void clear_ibs_nmi(void) |
448 | * if available (AMD Family10h rev B0 and later) | ||
449 | */ | ||
450 | static void setup_ibs(void) | ||
451 | { | 393 | { |
452 | ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); | 394 | if (has_ibs) |
395 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); | ||
396 | } | ||
397 | |||
398 | /* initialize the APIC for the IBS interrupts if available */ | ||
399 | static void ibs_init(void) | ||
400 | { | ||
401 | has_ibs = boot_cpu_has(X86_FEATURE_IBS); | ||
453 | 402 | ||
454 | if (!ibs_allowed) | 403 | if (!has_ibs) |
455 | return; | 404 | return; |
456 | 405 | ||
457 | if (pfm_amd64_setup_eilvt()) { | 406 | if (init_ibs_nmi()) { |
458 | ibs_allowed = 0; | 407 | has_ibs = 0; |
459 | return; | 408 | return; |
460 | } | 409 | } |
461 | 410 | ||
462 | printk(KERN_INFO "oprofile: AMD IBS detected\n"); | 411 | printk(KERN_INFO "oprofile: AMD IBS detected\n"); |
463 | } | 412 | } |
464 | 413 | ||
465 | 414 | static void ibs_exit(void) | |
466 | /* | ||
467 | * unitialize the APIC for the IBS interrupts if needed on AMD Family10h | ||
468 | * rev B0 and later */ | ||
469 | static void clear_ibs_nmi(void) | ||
470 | { | 415 | { |
471 | if (ibs_allowed) | 416 | if (!has_ibs) |
472 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); | 417 | return; |
418 | |||
419 | clear_ibs_nmi(); | ||
473 | } | 420 | } |
474 | 421 | ||
475 | static int (*create_arch_files)(struct super_block *sb, struct dentry *root); | 422 | static int (*create_arch_files)(struct super_block *sb, struct dentry *root); |
@@ -486,7 +433,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) | |||
486 | if (ret) | 433 | if (ret) |
487 | return ret; | 434 | return ret; |
488 | 435 | ||
489 | if (!ibs_allowed) | 436 | if (!has_ibs) |
490 | return ret; | 437 | return ret; |
491 | 438 | ||
492 | /* model specific files */ | 439 | /* model specific files */ |
@@ -519,7 +466,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) | |||
519 | 466 | ||
520 | static int op_amd_init(struct oprofile_operations *ops) | 467 | static int op_amd_init(struct oprofile_operations *ops) |
521 | { | 468 | { |
522 | setup_ibs(); | 469 | ibs_init(); |
523 | create_arch_files = ops->create_files; | 470 | create_arch_files = ops->create_files; |
524 | ops->create_files = setup_ibs_files; | 471 | ops->create_files = setup_ibs_files; |
525 | return 0; | 472 | return 0; |
@@ -527,10 +474,21 @@ static int op_amd_init(struct oprofile_operations *ops) | |||
527 | 474 | ||
528 | static void op_amd_exit(void) | 475 | static void op_amd_exit(void) |
529 | { | 476 | { |
530 | clear_ibs_nmi(); | 477 | ibs_exit(); |
531 | } | 478 | } |
532 | 479 | ||
533 | #endif | 480 | #else |
481 | |||
482 | /* no IBS support */ | ||
483 | |||
484 | static int op_amd_init(struct oprofile_operations *ops) | ||
485 | { | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static void op_amd_exit(void) {} | ||
490 | |||
491 | #endif /* CONFIG_OPROFILE_IBS */ | ||
534 | 492 | ||
535 | struct op_x86_model_spec const op_amd_spec = { | 493 | struct op_x86_model_spec const op_amd_spec = { |
536 | .init = op_amd_init, | 494 | .init = op_amd_init, |