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>
This commit is contained in:
Robert Richter 2008-07-22 21:08:57 +02:00 committed by Ingo Molnar
parent 7939d2bf7e
commit 7d77f2dcae

View file

@ -356,9 +356,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs)
}
}
static u8 ibs_eilvt_off;
static inline void apic_init_ibs_nmi_per_cpu(void *arg)
{
setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
}
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)
setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
}
static int pfm_amd64_setup_eilvt(void)
{
#define IBSCTL_LVTOFFSETVAL (1 << 8)
#define IBSCTL 0x1cc
struct pci_dev *cpu_cfg;
int nodes;
u32 value = 0;
/* per CPU setup */
on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 0, 1);
nodes = 0;
cpu_cfg = NULL;
do {
cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_10H_NB_MISC,
cpu_cfg);
if (!cpu_cfg)
break;
++nodes;
pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
| IBSCTL_LVTOFFSETVAL);
pci_read_config_dword(cpu_cfg, IBSCTL, &value);
if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
"IBSCTL = 0x%08x", value);
return 1;
}
} while (1);
if (!nodes) {
printk(KERN_DEBUG "No CPU node configured for IBS");
return 1;
}
#ifdef CONFIG_NUMA
/* Sanity check */
/* Works only for 64bit with proper numa implementation. */
if (nodes != num_possible_nodes()) {
printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
"found: %d, expected %d",
nodes, num_possible_nodes());
return 1;
}
#endif
return 0;
}
/*
* initialize the APIC for the IBS interrupts
* if needed on AMD Family10h rev B0 and later
* if available (AMD Family10h rev B0 and later)
*/
static void setup_ibs(void)
{
struct pci_dev *gh_device = NULL;
u32 low, high;
u8 vector;
ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
if (!ibs_allowed)
return;
/* This gets the APIC_EILVT_LVTOFF_IBS value */
vector = setup_APIC_eilvt_ibs(0, 0, 1);
/*see if the IBS control register is already set correctly*/
/*remove this when we know for sure it is done
in the kernel init*/
rdmsr(MSR_AMD64_IBSCTL, low, high);
if ((low & (IBS_CTL_LVT_OFFSET_VALID_BIT | vector)) !=
(IBS_CTL_LVT_OFFSET_VALID_BIT | vector)) {
/**** Be sure to run loop until NULL is returned to
decrement reference count on any pci_dev structures
returned ****/
while ((gh_device = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_10H_NB_MISC, gh_device))
!= NULL) {
/* This code may change if we can find a proper
* way to get at the PCI extended config space */
pci_write_config_dword(
gh_device, IBS_LVT_OFFSET_PCI,
(vector | IBS_CTL_LVT_OFFSET_VALID_BIT));
}
}
on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1, 1);
if (pfm_amd64_setup_eilvt())
ibs_allowed = 0;
}