diff options
author | Robert Richter <robert.richter@amd.com> | 2008-07-22 15:08:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-26 05:48:07 -0400 |
commit | 7d77f2dcae37cf232950cd0181fb0a2cddb18130 (patch) | |
tree | 1c1a04ed105a250ea4761d746f52369065270d84 /arch/x86/oprofile | |
parent | 7939d2bf7e30353d40d14f967b7fe2b2a7be5bd9 (diff) |
OProfile: change IBS interrupt initialization
Signed-off-by: Robert Richter <robert.richter@amd.com>
Cc: oprofile-list <oprofile-list@lists.sourceforge.net>
Cc: Barry Kasindorf <barry.kasindorf@amd.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r-- | arch/x86/oprofile/op_model_athlon.c | 84 |
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 | ||
359 | static u8 ibs_eilvt_off; | ||
360 | |||
359 | static inline void apic_init_ibs_nmi_per_cpu(void *arg) | 361 | static 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 | ||
364 | static inline void apic_clear_ibs_nmi_per_cpu(void *arg) | 366 | static 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 | ||
371 | static 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 | */ |
373 | static void setup_ibs(void) | 423 | static 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 | ||