aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/oprofile/op_model_athlon.c84
1 files changed, 54 insertions, 30 deletions
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c
index a2c8e2e372bb..90193b1538a0 100644
--- a/arch/x86/oprofile/op_model_athlon.c
+++ b/arch/x86/oprofile/op_model_athlon.c
@@ -356,9 +356,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs)
356 } 356 }
357} 357}
358 358
359static u8 ibs_eilvt_off;
360
359static inline void apic_init_ibs_nmi_per_cpu(void *arg) 361static inline void apic_init_ibs_nmi_per_cpu(void *arg)
360{ 362{
361 setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); 363 ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
362} 364}
363 365
364static inline void apic_clear_ibs_nmi_per_cpu(void *arg) 366static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
@@ -366,45 +368,67 @@ static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
366 setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); 368 setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
367} 369}
368 370
371static int pfm_amd64_setup_eilvt(void)
372{
373#define IBSCTL_LVTOFFSETVAL (1 << 8)
374#define IBSCTL 0x1cc
375 struct pci_dev *cpu_cfg;
376 int nodes;
377 u32 value = 0;
378
379 /* per CPU setup */
380 on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 0, 1);
381
382 nodes = 0;
383 cpu_cfg = NULL;
384 do {
385 cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
386 PCI_DEVICE_ID_AMD_10H_NB_MISC,
387 cpu_cfg);
388 if (!cpu_cfg)
389 break;
390 ++nodes;
391 pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
392 | IBSCTL_LVTOFFSETVAL);
393 pci_read_config_dword(cpu_cfg, IBSCTL, &value);
394 if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
395 printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
396 "IBSCTL = 0x%08x", value);
397 return 1;
398 }
399 } while (1);
400
401 if (!nodes) {
402 printk(KERN_DEBUG "No CPU node configured for IBS");
403 return 1;
404 }
405
406#ifdef CONFIG_NUMA
407 /* Sanity check */
408 /* Works only for 64bit with proper numa implementation. */
409 if (nodes != num_possible_nodes()) {
410 printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
411 "found: %d, expected %d",
412 nodes, num_possible_nodes());
413 return 1;
414 }
415#endif
416 return 0;
417}
418
369/* 419/*
370 * initialize the APIC for the IBS interrupts 420 * initialize the APIC for the IBS interrupts
371 * if needed on AMD Family10h rev B0 and later 421 * if available (AMD Family10h rev B0 and later)
372 */ 422 */
373static void setup_ibs(void) 423static void setup_ibs(void)
374{ 424{
375 struct pci_dev *gh_device = NULL;
376 u32 low, high;
377 u8 vector;
378
379 ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); 425 ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
380 426
381 if (!ibs_allowed) 427 if (!ibs_allowed)
382 return; 428 return;
383 429
384 /* This gets the APIC_EILVT_LVTOFF_IBS value */ 430 if (pfm_amd64_setup_eilvt())
385 vector = setup_APIC_eilvt_ibs(0, 0, 1); 431 ibs_allowed = 0;
386
387 /*see if the IBS control register is already set correctly*/
388 /*remove this when we know for sure it is done
389 in the kernel init*/
390 rdmsr(MSR_AMD64_IBSCTL, low, high);
391 if ((low & (IBS_CTL_LVT_OFFSET_VALID_BIT | vector)) !=
392 (IBS_CTL_LVT_OFFSET_VALID_BIT | vector)) {
393
394 /**** Be sure to run loop until NULL is returned to
395 decrement reference count on any pci_dev structures
396 returned ****/
397 while ((gh_device = pci_get_device(PCI_VENDOR_ID_AMD,
398 PCI_DEVICE_ID_AMD_10H_NB_MISC, gh_device))
399 != NULL) {
400 /* This code may change if we can find a proper
401 * way to get at the PCI extended config space */
402 pci_write_config_dword(
403 gh_device, IBS_LVT_OFFSET_PCI,
404 (vector | IBS_CTL_LVT_OFFSET_VALID_BIT));
405 }
406 }
407 on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1, 1);
408} 432}
409 433
410 434