OProfile: change IBS interrupt initialization
authorRobert Richter <robert.richter@amd.com>
Tue, 22 Jul 2008 19:08:57 +0000 (21:08 +0200)
committerIngo Molnar <mingo@elte.hu>
Sat, 26 Jul 2008 09:48:07 +0000 (11:48 +0200)
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>
arch/x86/oprofile/op_model_athlon.c

index a2c8e2e372bbb8cf9685b2182b81a74b645f8f69..90193b1538a03d3545c8015cb21768e0ea881dc9 100644 (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;
 }