aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2010-10-25 10:58:34 -0400
committerRobert Richter <robert.richter@amd.com>2010-10-25 10:58:34 -0400
commit4cafc4b8d7219b70e15f22e4a51b3ce847810caf (patch)
tree8051ea3f36f0682d08f47df8e35e14ca7eb7a5d7 /arch/x86/oprofile
parentb47fad3bfb5940cc3e28a1c69716f6dc44e4b7e6 (diff)
parentdbd1e66e04558a582e673bc4a9cd933ce0228d93 (diff)
Merge branch 'oprofile/core' into oprofile/x86
Conflicts: arch/x86/oprofile/op_model_amd.c Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r--arch/x86/oprofile/op_model_amd.c132
1 files changed, 117 insertions, 15 deletions
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index 65f0a1eb6b86..8d17db266bbf 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -71,7 +71,7 @@ static struct ibs_state ibs_state;
71 * IBS cpuid feature detection 71 * IBS cpuid feature detection
72 */ 72 */
73 73
74#define IBS_CPUID_FEATURES 0x8000001b 74#define IBS_CPUID_FEATURES 0x8000001b
75 75
76/* 76/*
77 * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but 77 * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
@@ -314,6 +314,74 @@ static void op_amd_stop_ibs(void)
314 wrmsrl(MSR_AMD64_IBSOPCTL, 0); 314 wrmsrl(MSR_AMD64_IBSOPCTL, 0);
315} 315}
316 316
317static inline int eilvt_is_available(int offset)
318{
319 /* check if we may assign a vector */
320 return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
321}
322
323static inline int ibs_eilvt_valid(void)
324{
325 u64 val;
326 int offset;
327
328 rdmsrl(MSR_AMD64_IBSCTL, val);
329 if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
330 pr_err(FW_BUG "cpu %d, invalid IBS "
331 "interrupt offset %d (MSR%08X=0x%016llx)",
332 smp_processor_id(), offset,
333 MSR_AMD64_IBSCTL, val);
334 return 0;
335 }
336
337 offset = val & IBSCTL_LVT_OFFSET_MASK;
338
339 if (eilvt_is_available(offset))
340 return !0;
341
342 pr_err(FW_BUG "cpu %d, IBS interrupt offset %d "
343 "not available (MSR%08X=0x%016llx)",
344 smp_processor_id(), offset,
345 MSR_AMD64_IBSCTL, val);
346
347 return 0;
348}
349
350static inline int get_ibs_offset(void)
351{
352 u64 val;
353
354 rdmsrl(MSR_AMD64_IBSCTL, val);
355 if (!(val & IBSCTL_LVT_OFFSET_VALID))
356 return -EINVAL;
357
358 return val & IBSCTL_LVT_OFFSET_MASK;
359}
360
361static void setup_APIC_ibs(void)
362{
363 int offset;
364
365 offset = get_ibs_offset();
366 if (offset < 0)
367 goto failed;
368
369 if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
370 return;
371failed:
372 pr_warn("oprofile: IBS APIC setup failed on cpu #%d\n",
373 smp_processor_id());
374}
375
376static void clear_APIC_ibs(void)
377{
378 int offset;
379
380 offset = get_ibs_offset();
381 if (offset >= 0)
382 setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
383}
384
317#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX 385#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
318 386
319static void op_mux_switch_ctrl(struct op_x86_model_spec const *model, 387static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
@@ -424,13 +492,13 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
424 } 492 }
425 493
426 if (ibs_caps) 494 if (ibs_caps)
427 setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); 495 setup_APIC_ibs();
428} 496}
429 497
430static void op_amd_cpu_shutdown(void) 498static void op_amd_cpu_shutdown(void)
431{ 499{
432 if (ibs_caps) 500 if (ibs_caps)
433 setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); 501 clear_APIC_ibs();
434} 502}
435 503
436static int op_amd_check_ctrs(struct pt_regs * const regs, 504static int op_amd_check_ctrs(struct pt_regs * const regs,
@@ -493,16 +561,11 @@ static void op_amd_stop(struct op_msrs const * const msrs)
493 op_amd_stop_ibs(); 561 op_amd_stop_ibs();
494} 562}
495 563
496static int __init_ibs_nmi(void) 564static int setup_ibs_ctl(int ibs_eilvt_off)
497{ 565{
498#define IBSCTL_LVTOFFSETVAL (1 << 8)
499#define IBSCTL 0x1cc
500 struct pci_dev *cpu_cfg; 566 struct pci_dev *cpu_cfg;
501 int nodes; 567 int nodes;
502 u32 value = 0; 568 u32 value = 0;
503 u8 ibs_eilvt_off;
504
505 ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
506 569
507 nodes = 0; 570 nodes = 0;
508 cpu_cfg = NULL; 571 cpu_cfg = NULL;
@@ -514,21 +577,60 @@ static int __init_ibs_nmi(void)
514 break; 577 break;
515 ++nodes; 578 ++nodes;
516 pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off 579 pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
517 | IBSCTL_LVTOFFSETVAL); 580 | IBSCTL_LVT_OFFSET_VALID);
518 pci_read_config_dword(cpu_cfg, IBSCTL, &value); 581 pci_read_config_dword(cpu_cfg, IBSCTL, &value);
519 if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { 582 if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
520 pci_dev_put(cpu_cfg); 583 pci_dev_put(cpu_cfg);
521 printk(KERN_DEBUG "Failed to setup IBS LVT offset, " 584 printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
522 "IBSCTL = 0x%08x", value); 585 "IBSCTL = 0x%08x\n", value);
523 return 1; 586 return -EINVAL;
524 } 587 }
525 } while (1); 588 } while (1);
526 589
527 if (!nodes) { 590 if (!nodes) {
528 printk(KERN_DEBUG "No CPU node configured for IBS"); 591 printk(KERN_DEBUG "No CPU node configured for IBS\n");
529 return 1; 592 return -ENODEV;
593 }
594
595 return 0;
596}
597
598static int force_ibs_eilvt_setup(void)
599{
600 int i;
601 int ret;
602
603 /* find the next free available EILVT entry */
604 for (i = 1; i < 4; i++) {
605 if (!eilvt_is_available(i))
606 continue;
607 ret = setup_ibs_ctl(i);
608 if (ret)
609 return ret;
610 return 0;
530 } 611 }
531 612
613 printk(KERN_DEBUG "No EILVT entry available\n");
614
615 return -EBUSY;
616}
617
618static int __init_ibs_nmi(void)
619{
620 int ret;
621
622 if (ibs_eilvt_valid())
623 return 0;
624
625 ret = force_ibs_eilvt_setup();
626 if (ret)
627 return ret;
628
629 if (!ibs_eilvt_valid())
630 return -EFAULT;
631
632 pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
633
532 return 0; 634 return 0;
533} 635}
534 636